7.25T3

唯一一道不水的题,让我改了两天,什么破情况,昨天晚上真的改到自闭,回到正题

一个环,要求把颜色一样的挪到一起,这种题一般第一步都是,拆环为链变二倍,然后怎么办呢?枚举每个断点,看这么断的最少移动次数,这就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 }
View Code

猜你喜欢

转载自www.cnblogs.com/hzjuruo/p/11253702.html
今日推荐