POJ-1063 Flip and Shift 数学分析&运用守恒定理
题意:给定一个数N (10 <=N <= 30),然后给你N个数,这N个数由0和1组成,这N个数可以看做是一个环.然后现在又一种操作,可以将连续的三个数进行翻转,也可以将整个序列顺时针旋转一圈.现在问是否存在通过一个操作来是的实现将所有的1都靠在一起.
这题刚开始分析的时候只注意到连续的三个数的8种组合情况,然后只有四种情况是在翻转过程中产生变化的.但是这样的想法还是没有多大帮助.实在是不会了.因为我的整个思路在于去构造一个方法能够使得所有的1都连在一起.而题目只要我们输出YES或者是NO.参看了题解后恍然大悟:这里只要从奇偶性方面去思考就可以了.
当我们从奇偶性去看一个状态的时候,最后的状态是什么呢,所有的1都连在一起,如果是奇数个1的话,那么1所有位置的奇偶性之差为1,偶数个1则为零.我们在观察其实所谓的翻转就是将某个点的坐标+或者是-2,这并不影响其奇偶性. 当N为奇数的时候,那么一直+2的话,那么最后的时候会出现N和1两个奇数连着的情况,因此奇偶性发生了突变.也就是我如果N是奇数的话,那么我们能够构造出1在奇数位置和偶数位置的差不超过1.如果N为偶数的话,那么无论如何翻转,奇偶性终将不变,因此如果初始状态不满足的话就输出NO了.
综上所述:
当N为奇数的时候,总是输出YES
当N为偶数的时候,如果出现在奇数位上的1和偶数位上的1之差不超过1的话输出YES,否则输出NO
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #define MAXN 35 using namespace std; int main() { int T, N; scanf("%d", &T); while (T--) { int odd = 0, even = 0; int c; scanf("%d", &N); for (int i = 0; i < N; ++i) { scanf("%d", &c); if (c) i&1 ? ++odd : ++even; } if (N & 1) puts("YES"); else puts(abs(odd-even)<=1 ? "YES" : "NO"); } return 0; }