POJ 3276

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

你可能感兴趣的:(poj)