十分困倦而sb的一天。
期望得分:100+100+0
实际得分:100+10+0
A. 匹配
一开始看题,前缀后缀最长匹配?kmp!
然后再看,hash就完事了,好打还复杂度低。
一会瞎推了下码完,后来因为T3没思路还来写了个对拍。发现暴力比正解快,然后看到输出的 0 0 0 0... 然后就懂了233。
PS:居然拍出了一组答案1w多的数据,欧皇ha
正解:KMP 在A串求next[],然后跑B串,最后的匹配长度就是ans
或者。。。 hash nb! 直接$O(n)$
B. 回家
下次看到“我认为的”水题,一定一定一定要要要验证验证验证正确性正确性正确性!
这题我打个了Tarjan 判割点判连通然后就撂了
hack数据:
1
5 5
1 5
1 2
5 2
2 3
3 4
正解:必过点一定是割点,而割点不一定是必过点。如以上数据,既然都到了5了还往下走个**啊
于是我们要给必过点一个严谨的定义:
必过点,就是去掉了就一定不能达到目的地。换言之就是去掉该点,1点与n点不连通 断开分属于两个连通块。
解法一:
点双里的点不符合必过点的定义,然后我们就缩个点把它干掉,建出圆方树。
然后根据定义我们可以这样找,把1作为根,如果n点在该点且该点非1/n点的子树里,则该点是必过点。
证明:树上的两点间有且仅有一条简单路径,n点的祖先都是1到n点圆方树上的的简单路径上的点,去掉任何一个都会使1 n不连通,符合必过点定义,得证。
接下来就可以dfs搞定了。
解法二:
我们可以不建出圆方树,因为Tarjan时就有搜索树结构,类似于BLO那题,我们只要特判反祖就可以了。
if(dfn[u]<=low[v]&&dfn[v]<=dfn[n])
只要在判割点时多加一句话,然后就可以AC。
我们来证明下它的正确性:
首先第一个判断,保证了这个儿子的子树不存在反祖,我们就可以按照树来处理。 可以通过上面hack数据来看这个判断的作用。
第二个判断,保证了n在v的子树里,同时==考虑了v就是n的情况,以下是对于判断二的证明:
分类讨论下: 以下n树代表的是含有n的子树,而非n的子树
1.先v树后n树,dfn[n]还未更新,条件不成立
2.v树即是n树,a. v!=n 知v先赋dfn,n后赋 成立
b. v==n dfn[v]==dfn[n] 成立
3.先n树后v树,即访问顺序为先n后v,则dfn[v]>dfn[n] 不成立
得证。
我们再来证另一种相似写法的错误性:
if(dfn[u]<=low[v]&&dfn[u]<dfn[n])
假设一个非根结点u有两个搜索树儿子,一个儿子h无返祖,另一个儿子g的子树含有n且返祖,u节点的父亲节点为f。
如果从u第一次进入的是g,则会更新dfn[n],此时条件一不满足,条件二满足
第二次进入h,此时条件一满足,条件二元素不变,依然满足 同时满足判定u为必过点
但显然u在点双中,不符,得证。
C. 寿司
考试的时候想到了断环成链,枚举特殊点,但并没有想到向区间两边分别集中这种较容易处理的计算方法(我想往区间中央集中,然后不会算),实际上这是tm的等效的啊!R到中央B不就到**的两边了嘛,正难则反啊!我*$%&^#$^%$
然后我就puts("0");了。。。
说几种思路:
$O(n^2)$ 枚举区间,枚举断点,从断点为分水岭向两侧集中颜色,预处理出贡献即可。
$O(nlog_{1.5}n)$ gmk考场上想出来的。我们发现对于同一个区间,ans关于断点位置呈单峰函数状(U),然后我们可以外侧枚举区间,对于同一个区间用三分找谷底,最后对所有区间的ans最小值取min。
$O(nlog_2 n)$ 转网上题解的话:显然,这样做的答案,应该是,每一个被移到左边去的R左边原来的B的个数,每一个被移到右边去的R右边原来的B的个数,那么很显然的,我们最好的方式是将,第(B的总个数 + 1) / 2个B(以下将第(B的总个数 + 1) / 2个B的位置简称为pos)左边的R全部移到左边,右边的R移到右边。
虽然我并不觉得显然。。。 然后就可以二分那个pos,使左边的B个数贴近cnt_B/2
不难发现二分的是决策点(再带入计算)而三分的是ans
$O(n)$ 我们通过三分和二分 发现决策点j是不会左移的,严谨的证明wd已给出。 然后我们就不用二分决策点j了,用单调指针j直接扫即可。
关于计算:
wd大神给出了等差数列和位置求和,其做法的原因是各个点的贡献呈阶梯状(脑补脑补)。
我们不妨直接处理出所有R点的阶梯前缀答案,然后发现区间外的贡献对所有R点来说是可以计算的(一整块),然后做差就可以求出[l,r]区间内的贡献了。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 #define int long long 6 #define reg register 7 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i)) 8 using namespace std; 9 inline int read(); 10 const int LEN=2000005; 11 char s[LEN]; 12 int sl[LEN],sr[LEN],bl[LEN],rl[LEN],br[LEN],rr[LEN]; 13 int len; 14 int calcl(int l,int r) 15 { 16 return sl[r]-sl[l-1]-bl[l-1]*(rl[r]-rl[l-1]); 17 } 18 int calcr(int l,int r) 19 { 20 return sr[l]-sr[r+1]-br[r+1]*(rr[l]-rr[r+1]); 21 } 22 int calc(int l,int m,int r) 23 { 24 return calcl(l,m)+calcr(m+1,r); 25 } 26 int sf(int l,int r) 27 { 28 // printf("L=%lld R=%lld ",l,r); 29 int ml,mr,L=l,R=r; 30 while(r-l>2) 31 { 32 ml=(r-l+1)/3+l; 33 mr=(r-l+1)*2/3+l; 34 if(calc(L,ml,R)>calc(L,mr,R)) l=ml; 35 else r=mr; 36 } 37 return min(calc(L,l,R),min(calc(L,l+1,R),calc(L,r,R))); 38 } 39 signed main() 40 { 41 int T=read(); 42 while(T--) 43 { 44 scanf("%s",s+1); 45 len=strlen(s+1); 46 int lim=len<<1; 47 F(i,len+1,lim) s[i]=s[i-len]; 48 F(i,1,lim) 49 { 50 sl[i]=sl[i-1]; 51 bl[i]=bl[i-1]; 52 rl[i]=rl[i-1]; 53 if(s[i]=='B') ++bl[i]; 54 else 55 { 56 sl[i]+=bl[i]; 57 ++rl[i]; 58 } 59 // printf("i=%d %c %d %d %d ",i,s[i],sl[i],bl[i],rl[i]); 60 } 61 for(reg int i=lim;i>=1;--i) 62 { 63 sr[i]=sr[i+1]; 64 br[i]=br[i+1]; 65 rr[i]=rr[i+1]; 66 if(s[i]=='B') ++br[i]; 67 else 68 { 69 sr[i]+=br[i]; 70 ++rr[i]; 71 } 72 } 73 int ans=0x3f3f3f3f3f3f3f3f; 74 F(i,1,len) ans=min(ans,sf(i,i+len-1)); 75 printf("%lld ",ans); 76 } 77 return 0; 78 } 79 inline int read() 80 { 81 int x=0; 82 char tc=getchar(); 83 while(tc<'0'||tc>'9') tc=getchar(); 84 while(tc>='0'&&tc<='9') 85 { 86 x=x*10+tc-48; 87 tc=getchar(); 88 } 89 return x; 90 }
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 #define int long long 6 #define reg register 7 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i)) 8 using namespace std; 9 inline int read(); 10 const int LEN=2000005; 11 char s[LEN]; 12 int sl[LEN],sr[LEN],bl[LEN],rl[LEN],br[LEN],rr[LEN]; 13 int len; 14 int calcl(int l,int r) 15 { 16 return sl[r]-sl[l-1]-bl[l-1]*(rl[r]-rl[l-1]); 17 } 18 int calcr(int l,int r) 19 { 20 return sr[l]-sr[r+1]-br[r+1]*(rr[l]-rr[r+1]); 21 } 22 int calc(int l,int m,int r) 23 { 24 return min(calcl(l,m)+calcr(m+1,r),calcl(l,m-1)+calcr(m,r)); 25 } 26 signed main() 27 { 28 int T=read(); 29 while(T--) 30 { 31 scanf("%s",s+1); 32 len=strlen(s+1); 33 int lim=len<<1; 34 F(i,len+1,lim) s[i]=s[i-len]; 35 F(i,1,lim) 36 { 37 sl[i]=sl[i-1]; 38 bl[i]=bl[i-1]; 39 rl[i]=rl[i-1]; 40 if(s[i]=='B') ++bl[i]; 41 else 42 { 43 sl[i]+=bl[i]; 44 ++rl[i]; 45 } 46 } 47 for(reg int i=lim;i>=1;--i) 48 { 49 sr[i]=sr[i+1]; 50 br[i]=br[i+1]; 51 rr[i]=rr[i+1]; 52 if(s[i]=='B') ++br[i]; 53 else 54 { 55 sr[i]+=br[i]; 56 ++rr[i]; 57 } 58 } 59 int l,j=10,r; 60 int ans=0x3f3f3f3f3f3f3f3f; 61 F(i,1,len) 62 { 63 l=i; r=len+i-1; 64 /* F(i,1,lim) 65 { 66 if(i==l) putchar('['); 67 printf("%c",s[i]); 68 if(i==r) putchar(']'); 69 } 70 puts(""); 71 printf("cal=%lld ",calc(l,10,r));*/ 72 if(j<i) ++j; 73 while(calc(l,j,r)>=calc(l,j+1,r)) 74 { 75 ++j; 76 } 77 // printf("l=%lld j=%lld r=%lld c=%lld->%lld ",l,j,r,calc(l,j,r),calc(l,j+1,r)); 78 ans=min(ans,calc(l,j,r)); 79 } 80 printf("%lld ",ans); 81 } 82 return 0; 83 } 84 inline int read() 85 { 86 int x=0; 87 char tc=getchar(); 88 while(tc<'0'||tc>'9') tc=getchar(); 89 while(tc>='0'&&tc<='9') 90 { 91 x=x*10+tc-48; 92 tc=getchar(); 93 } 94 return x; 95 }