题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方。问:求最小操作m,再此基础上求k。
题解:1、5000头牛不是小数目,再怎么也得要n^2的算法,其中,枚举k是需要的,这就有n了,只能想办法给出一个n在O(n)时间内求出最小次数了。
2、对于给定的k,要想O(n)内把次数算出来,即只能扫一遍,一想到的必定是从前往后扫,遇到面朝后的就转头,但这一转牵扯太多,要改太多东西,k一大直接崩溃。
3、对于每次扫描到的第i个点,都至多只能改一次才能保证效率,即只改变化的。将牛的朝向弄成依赖型,即后者依赖于前者,这样在一个区间内[a,b]翻转时,实际上[a+1,b]的依赖关系是没有改变的,改变的只有a,b+1。
4、综上,设置一种关系表示每头牛与前一头牛的朝向,最简单的就是同向与反向的差异,不妨令同向为0,反向为1,为了使得最后都朝前,可以令一头虚拟牛(即0号牛)头朝前,然后第一头牛依赖于它。
5、因此,每次检查时,只需要更改a和a+k位置的牛的依赖关系便可以解决了,最后在检查一下剩余的牛是否全是0就结束了。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int cow[5005],temp[5005]; 6 int main() 7 { 8 int n; 9 while(scanf("%d",&n)!=EOF) 10 { 11 char ch,lc='F'; 12 for(int i=1;i<=n;i++) 13 { 14 scanf(" %c",&ch); 15 if(lc==ch) 16 cow[i]=0; 17 else 18 cow[i]=1; 19 lc=ch; 20 } 21 int ansk,ansm=1<<30; 22 for(int k=1;k<=n;k++) 23 { 24 int tp=0; 25 memcpy(temp,cow,sizeof(cow)); 26 for(int i=1;i<=n-k+1;i++) 27 if(temp[i]) 28 tp++,temp[i+k]^=1; 29 for(int i=n-k+2;i<=n;i++) 30 { 31 if(temp[i]) 32 { 33 tp=1<<30; 34 break; 35 } 36 } 37 if(ansm>tp) 38 { 39 ansm=tp; 40 ansk=k; 41 } 42 } 43 printf("%d %d\n",ansk,ansm); 44 } 45 return 0; 46 }