唯一一道不水的题,让我改了两天,什么破情况,昨天晚上真的改到自闭,回到正题
一个环,要求把颜色一样的挪到一起,这种题一般第一步都是,拆环为链变二倍,然后怎么办呢?枚举每个断点,看这么断的最少移动次数,这就O(n)起步了,再加个n什么之类的估计就死翘翘了,这题我没打部分分,就直接上正解了,(sdfz那大佬三分搞到65分,可惜我不会)
我们把BR的排列具化成01串,谁0谁1无所谓,我们假设把0留在中间,那么1被挪到两边需要的移动次数应该就是他移动的方向上0的个数,那么我们来想一下怎么移动最优?也就是怎么样能让每个1两边的0最少,当然是以中间的0为不懂点咯,那这样的话我们记录一下每个1两边0的个数就可以了,正着倒着扫一下就好了,我们来想一下这一个序列中所有的1一共要移动的次数,∑(qian[j]-qian[i-1])+∑(hou[j]-hou[i+len]),来理解一下这个式子,qian就是刚才记录的那个前面有几个0,hou记录后面有几个(倒着记录),j代表为1的点,qian[j]中的j为在中间0前面的点,hou[j]中的j为在中间0后面的点,i代表枚举开始的点,i+len-1是枚举结束的点,那这个式子就是用前缀和后缀算出中间一部分,现在我们把它拆开就变成了∑qian[j]-∑qian[i-1]+∑hou[j]-∑[i+len],仔细一看,这个qian[j],hou[j]的有点前缀和的意思啊,yes,就是前缀和,不对,准确来说是前缀和的前缀和以及后缀和的前缀和,那式子都有了,码就完了,虽然我码了很久。。附赠一下我最后推出来的完整的式子
ans=qh[mid]-qh[i-1]-qian[i-1]*len1+hh[mid+1]-hh[i+len]-hou[mid+1]*len2
len1=(mid-i+1)-(qian[mid]-qian[i-1])
len2=(i+len-1-(mid+1)+1)-(hou[mid]-hou[i+len])
我打的应该不太算正解,因为我拿到的正解需要二分,我实在不觉得决策具有单调性,所以放弃了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define maxn 1001000 5 #define int long long 6 using namespace std; 7 int t,len,tot,ans; 8 int cun[maxn*2],qian[maxn*2],hou[maxn*2],qh[maxn*2],hh[maxn*2],jl[maxn*2]; 9 char a[maxn]; 10 void clear() 11 { 12 tot=0; ans=200000000000000000; 13 memset(cun,0,sizeof(cun)); memset(qian,0,sizeof(qian)); 14 memset(hou,0,sizeof(hou)); memset(qh,0,sizeof(qh)); 15 memset(hh,0,sizeof(hh)); memset(jl,0,sizeof(jl)); 16 } 17 signed main() 18 { 19 scanf("%lld",&t); 20 while(t--) 21 { 22 clear(); 23 scanf("%s",a+1); len=strlen(a+1); 24 for(int i=1;i<=len;++i) 25 { 26 if(a[i]=='B') cun[i]=1; 27 else {cun[i]=0; tot++;} 28 } 29 for(int i=len+1;i<=2*len;++i) cun[i]=cun[i-len]; 30 int cnt=0; tot*=2; 31 for(int i=1;i<=2*len;++i) 32 { 33 if(cun[i]==0) {cnt++; jl[cnt]=i; qian[i]=cnt; hou[i]=tot-qian[i]+1;} 34 if(cun[i]==1) {qian[i]=cnt; hou[i]=tot-qian[i];} 35 if(cun[i]==0) qh[i]=qh[i-1]; 36 else qh[i]=qh[i-1]+qian[i]; 37 } 38 for(int i=2*len;i>=1;--i) 39 { 40 if(cun[i]==0) hh[i]=hh[i+1]; 41 else hh[i]=hh[i+1]+hou[i]; 42 } 43 for(int i=1;i<=len;++i) 44 { 45 int da=0; 46 int mid=(qian[i+len-1]-qian[i-1])/2+1+qian[i-1]; mid=jl[mid]; 47 da=qh[mid]-qh[i-1]-qian[i-1]*(mid-i+1-qian[mid]+qian[i-1]); 48 da+=hh[mid+1]-hh[i+len]-hou[i+len]*(i+len-mid-1-hou[mid+1]+hou[i+len]); 49 ans=min(ans,da); 50 } 51 printf("%lld\n",ans); 52 } 53 return 0; 54 }