poj1063 解题报告(poj 1063 analysis report)
题目:
一个循环序列,其中有若干0和1,两个间隔为1(即间隔一个数)的数的位置可以互换。问题是,给定一个这样的队列,判断是否可以将所有的0和1分别归拢到一起,即可以将此循环序列切断为两个序列,一个里面只有1,一个里面只有0.
思考:
题目不难,刚开始没有发现公式,考虑到的情况少了,所以wa了,后来考虑到所有情况,并总结了公式,就ac了。
证明:
引理1:相邻的两个数只有10,01,11,00 四种情况,其中00,11这两种情况对于整个循环序列没有影响。
证明:若存在11或00这两种组合,显然,通过在不同位置上执行数字互换操作(题目里所提),这种组合可以被移动到循环序列的任意指定位置。因此,当循环序列里面只有11和00时,我们可以非常简单地移动所有11(或00),让它们相连,这样循环序列就可以分成两个全0和全1的子序列。所以,11和00的存在不影响最终结果。
题目证明
1.如果循环序列的长度是奇数,那么此循环序列一定可以切断为两个序列,一个里面只有1,一个里面只有0.
证明:如果长度是奇数,那么一定有偶数个1+奇数个0,或者偶数个0+奇数个1.如果1和0的个数不相等,那么一定有11或00这种情况存在,因为n个0或1无法将n+1个1或0分开(注意,是循环序列,头和尾之间也需要插入数字分开)。又因为引理1,所以存在的00和11可以被消去,即不考虑,那么剩下的循环序列长度还是奇数,因此还存在00或11。这样一直消去,直到长度为1,长度为1的循环序列是一定满足要求的。
2.如果循环序列的长度是偶数,若0或1在偶数位上的数目与在奇数位上的数目之差小于等于1,那么此循环序列一定可以切断为两个序列,一个里面只有1,一个里面只有0.
证明:如果长度是偶数,假设里面有m个01,n个10(剩下的00和11根据引理1可以不考虑)。如果一个10和一个01相邻,则可以通过换位操作将1001变成1100。若m和n相等,则最后经过消去,没有数字剩下,因此这是个循环序列;若有m和n相差1,则最后经过消去,只剩下一个01或10,这也是一个循环序列;若m和n相差大于1,则剩下k个10或01,k>=2,例如:1010,这不是一个循环序列。所以,只有m和n的差小于等于1时,循环序列才满足题目要求。不失一般性地,设10中的1处于奇数位,01中的1处于偶数为,则只有在偶数位上的数目与在奇数位上的数目之差小于等于1时,才满足题目要求。
3.代码
1 #include<stdio.h> 2 #include<math.h> 3 int main() 4 { 5 int d[30],n,c; 6 scanf("%d",&n); 7 while(n>0) 8 { 9 int ow=0,ew=0; 10 scanf("%d",&c); 11 for(int i=0;i<c;i++) 12 scanf("%d",&d[i]); 13 if(c%2==1) 14 printf("YES\n"); 15 else 16 { 17 for(int i=0;i<c;i++) 18 { 19 if(d[i]==0) 20 { 21 if(i%2==0) 22 ow++; 23 else 24 ew++; 25 } 26 } 27 if(abs(ow-ew)<2) 28 printf("YES\n"); 29 else 30 printf("NO\n"); 31 } 32 n--; 33 } 34 return 0; 35 }