Codeforces1071C Triple Flips 【构造】【Four Russians】

题目分析:

这种题目显然可以先考虑哪些无解。我们发现我们不考虑操作次数的时候,我们可以选择连续的三个进行异或操作。

这样我们总能使得一个序列转化为$000...000xy$的形式。换句话说,对于$000...0001$,$000...0010$,$000...0011$考虑无解条件即可。

这时候写一个暴力程序,用$O(n^2*2^n)$的算法可以发现其中一个是总长小于$7$无解,另外两个是小于$8$无解。

然后观察题目要求的操作次数与$n/3$有关,不难想到每$3$个分成一组,然后在组内调成$0$,允许利用组外信息,每组只允许用一次操作。但这样操作数会超过($011 or 110$)。

那我们放宽一下限制,每$6$个分成一组,在组内调成$0$,允许利用组外信息,每组只允许操作两次。这样就可以了(我一开始以为$110111$是不行的,写了一个暴力后后来发现我脑残了)。

这样我们考虑Four Russians,预处理出来每$6$组怎么走,最后对剩余的暴力就行了。

 

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn = 102000;
  5 
  6 int n,a[maxn],f[1<<12];
  7 struct node{int x,y,z;};
  8 vector <node> des[64];
  9 
 10 void init(){
 11     queue<int> q;
 12     int N = 6;
 13     memset(f,0x3f,sizeof(f));
 14     f[0] = 0; q.push(0);
 15     while(!q.empty()){
 16     int k = q.front();q.pop();
 17     for(int i=0;i<N;i++){
 18         if(f[k^(1<<i)] > f[k] + 1){
 19         for(int j=0;j<des[k].size();j++)
 20             des[k^(1<<i)].push_back(des[k][j]);
 21         des[k^(1<<i)].push_back((node){i,6,12-i});
 22         f[k^(1<<i)] = f[k]+1;
 23         q.push(k^(1<<i));
 24         }
 25         for(int j=i+1;j<N;j++){
 26         int z = (1<<i)+(1<<j);
 27         if(j+(j-i) < N) z |= (1<<2*j-i);
 28         if(f[k^z] > f[k]+1){
 29             for(int fr=0;fr<des[k].size();fr++)
 30             des[k^z].push_back(des[k][fr]);
 31             des[k^z].push_back((node){i,j,2*j-i});
 32             f[k^z] = f[k]+1;
 33             q.push(k^z);
 34         }
 35         }
 36     }
 37     }
 38 }
 39 
 40 node opt[maxn];
 41 int num;
 42 
 43 node lst[maxn];
 44 
 45 void Remain(){
 46     queue<int> q;
 47     memset(f,0x3f,sizeof(f));
 48     //for(int i=0;i<64;i++) des[i].clear();
 49     f[0] = 0;q.push(0);
 50     int N = min(n,12);
 51     while(!q.empty()){
 52     int k = q.front();q.pop();
 53     for(int i=0;i<N;i++){
 54         for(int j=i+1;j<N;j++){
 55         if(j+(j-i) >= N) break;
 56         int z = (1<<i)+(1<<j)+(1<<2*j-i);
 57         if(f[k^z] > f[k]+1){
 58             f[k^z] = f[k]+1;
 59             lst[k^z] = (node){i,j,2*j-i};
 60             q.push(k^z);
 61         }
 62         }
 63     }
 64     }
 65     int z = 0;
 66     for(int i=n-N+1;i<=n;i++){z = (z<<1)+a[i];}
 67     if(f[z] > 1e8){puts("NO");}
 68     else{
 69     puts("YES");
 70     printf("%d\n",num+f[z]);
 71     for(int i=1;i<=num;i++){
 72         printf("%d %d %d\n",opt[i].x,opt[i].y,opt[i].z);
 73     }
 74     while(z){
 75         printf("%d %d %d\n",n-lst[z].z,n-lst[z].y,n-lst[z].x);
 76         int pp = z;
 77         z ^= (1<<lst[pp].x); z ^= (1<<lst[pp].y); z^= (1<<lst[pp].z);
 78     }
 79     }
 80 }
 81 
 82 void work(){
 83     for(int i=1;i<=n;i+=6){
 84     if(i+12 > n) break;
 85     int z = (a[i+5]<<5)+(a[i+4]<<4)+(a[i+3]<<3)+(a[i+2]<<2)+(a[i+1]<<1)+a[i];
 86     for(int j=0;j<des[z].size();j++){
 87         opt[++num] = des[z][j];
 88         opt[num].x += i; opt[num].y += i; opt[num].z += i;
 89         a[opt[num].x] ^= 1; a[opt[num].y] ^= 1; a[opt[num].z] ^= 1;
 90     }
 91     }
 92     Remain();
 93 }
 94 
 95 int main(){
 96     scanf("%d",&n);
 97     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 98     init();
 99     work();
100     return 0;
101 }

 

posted @ 2018-10-26 22:26  menhera  阅读(406)  评论(0编辑  收藏  举报