模拟测试20190725
考了最近最水的一套题,然而并没有能像考得时候YY的那样干上200(数组开小真是对不起了啊)
后两个小时疯狂划水,盯着T1毫无意义的对拍发呆,并没有想着去检查T2的数组开没开够(下次再颓cbx就不是人)
T3想了个错误思路,手模了几个点还和暴力跑的一样(放假就买彩票),于是自信满满得想象自己能AK,出成绩后直接完戏
T1:匹配
刚看到这题以为是kmp然而kmp已经快忘干净了,刚想打个暴力,打了个for突然发现这不hash傻逼吗,20分钟码了一个,成功水过
T2:回家
看第一眼看出来是tarjan,第二眼看出要求割点,第三眼看出要缩点双,第四眼看出要在新图跑dfs......
然而码的时候经历了模板炸死,样例写错,最终因数组开小re80的苦逼经过
缩点双一定要把数组开大几倍!!!血的教训!!!
T3:寿司
考试的时候本来码出来了40分暴力,然后自己YY了一个好似是正解的算法,头铁没有交暴力,10分GG
这题我考试的时候以为一定是把一种颜色移到两边,但是没有考虑一个点从1交换到n的情况(完戏)
正确做法是枚举将序列分开的端点,然后统计这个区间把一种颜色移到两边的最优答案
具体分析:经过观察我们发现最优答案一定是把一个分界点左边的移到左端点,右边的移到右端点的答案
而我们还发现这个端点一定左右各有一半另一种颜色(往左往右都不会更优),所以这个端点可以二分找到,总复杂度O(nlogn),勉强卡过
而根据上面的结论,我们发现在左右端点变化的时候,这个中点只可能往右走而不可能往左走,即具有单调性
所以我们可以用一个指针来代表中点,每次右移到满足条件的位置就好了,总复杂度O(n)
PS:好多人问一个区间知道了中点怎么才能O(1)求,这里简单说一下
把原字符串复制接在原串后,处理出来在新串里[1,i]所有红色左移到最左的花费sl,[i,n*2]所有红色右移到最右的花费sr,每个点左右有多少个红色rl,rr和蓝色bl,br,我们考虑把区间[l,mid]的红色移到最左(右移同理)则有 ans=sl[mid](所有的)-sl[l-1](超出l的)-(rl[mid]-rl[l-1])*bl[l-1](跨l的)
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define re register 4 using namespace std; 5 inline ll min(const ll x,const ll y){ 6 return x<y? x:y; 7 } 8 int lb[2000010],rb[2000010],lr[2000010],rr[2000010];ll slb[2000010],srb[2000010]; 9 char s[2000010]; 10 inline ll solve(const int l,const int r){ 11 ll ans,L=l,R=r,to=(lr[r]-lr[l-1])>>1; 12 while(L<R){ 13 re int mid=L+R>>1; 14 if(lr[mid]-lr[l-1]>to) R=mid; 15 else L=mid+1; 16 } 17 ans=slb[L-1]-1ll*(lb[L-1]-lb[l-1])*lr[l-1]+srb[L]-1ll*(rb[L]-rb[r+1])*rr[r+1]-slb[l-1]-srb[r+1]; 18 return ans; 19 } 20 int main(){ 21 int T,l,num,sum;ll ans=0; 22 scanf("%d",&T); 23 while(T--){ 24 scanf("%s",s+1); l=strlen(s+1); sum=0; 25 for(re int i=1;i<=l;i++) s[i+l]=s[i]; 26 lb[0]=lr[0]=slb[0]=0; 27 for(re int i=1;i<=l*2;i++){ 28 slb[i]=slb[i-1]; 29 lb[i]=lb[i-1]; lr[i]=lr[i-1]; 30 if(s[i]=='R') lr[i]++; 31 else lb[i]++,slb[i]+=lr[i]; 32 } 33 rb[l<<1|1]=rr[l<<1|1]=srb[l<<1|1]=0; 34 for(re int i=l*2;i>=1;i--){ 35 srb[i]=srb[i+1]; 36 rb[i]=rb[i+1]; rr[i]=rr[i+1]; 37 if(s[i]=='R') rr[i]++; 38 else rb[i]++,srb[i]+=rr[i]; 39 } 40 ans=0x7fffffffffffffff; 41 for(int i=1;i<=l;i++){ 42 ans=min(ans,solve(i,i+l-1)); 43 } 44 printf("%lld\n",ans); 45 } 46 }
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define re register 4 using namespace std; 5 inline ll min(const ll x,const ll y){ 6 return x<y? x:y; 7 } 8 int lb[2000010],rb[2000010],lr[2000010],rr[2000010];ll slb[2000010],srb[2000010]; 9 char s[2000010]; 10 inline ll solve(const int l,const int r,const int L){ 11 return slb[L-1]-1ll*(lb[L-1]-lb[l-1])*lr[l-1]+srb[L]-1ll*(rb[L]-rb[r+1])*rr[r+1]-slb[l-1]-srb[r+1]; 12 } 13 int main(){ 14 int T,l,num,sum,div;ll ans=0; 15 scanf("%d",&T); 16 while(T--){ 17 scanf("%s",s+1); l=strlen(s+1); sum=0; 18 for(re int i=1;i<=l;i++) s[i+l]=s[i]; 19 lb[0]=lr[0]=slb[0]=0; 20 for(re int i=1;i<=l*2;i++){ 21 slb[i]=slb[i-1]; 22 lb[i]=lb[i-1]; lr[i]=lr[i-1]; 23 if(s[i]=='R') lr[i]++; 24 else lb[i]++,slb[i]+=lr[i]; 25 } 26 rb[l<<1|1]=rr[l<<1|1]=srb[l<<1|1]=0; 27 for(re int i=l*2;i>=1;i--){ 28 srb[i]=srb[i+1]; 29 rb[i]=rb[i+1]; rr[i]=rr[i+1]; 30 if(s[i]=='R') rr[i]++; 31 else rb[i]++,srb[i]+=rr[i]; 32 } 33 ans=0x7fffffffffffffff;div=1; 34 for(int i=1;i<=l;i++){ 35 while(div!=i+l-1&&lb[div]-lb[i-1]<=(lb[i+l-1]-lb[i-1])/2) div++; 36 ans=min(ans,solve(i,i+l-1,div)); 37 } 38 printf("%lld\n",ans); 39 } 40 }