题意: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 }