1. 程式人生 > >Codeforces 1071 C - Triple Flips

Codeforces 1071 C - Triple Flips

C - Triple Flips

思路:

小範圍暴力

大範圍遞迴構造

構造方法:

solve(l, r) 表示使l 到 r 區間全變為0的方法

為了使反轉次數小於等於n/3 + 12

我們只需要保證每次反轉後區間長度減少值的期望為3就可以了

如果a[l] == 0, l++

如果a[r] == 0, r--

如果a[l] == 1 && a[l+1] == 1 && a[l+2] == 1, 反轉這三個就可以啦, l += 3

如果a[l] == 1 && a[l+1] == 0 && a[l+2] == 1, 反轉l, l+2, l+4這三個, l += 3

如果a[l] == 1 && a[l+1] == 0 && a[l+1] == 0, 反轉l, l+3, l+6這三個, l += 3

從右區間減少同理

否則只剩下這種情況了:

1 1 ...... 1 1

那麼只需要根據區間長度的奇偶性

反轉l , (l+r)/2, r 和 l+1 , (l+1+r-1)/2, r-1 或者 l, (l+r-1)/2, r-1 和 l+1 , (l+1+r)/2, r 

然後 l += 2, r -= 2, 區間長度減少4

區間長度小於8的話就暴力

用二進位制列舉所有的反轉情況, 然後檢查

程式碼:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pi acos(-1.0)
#define LL long long
//#define mp make_pair
#define pb push_back
#define ls rt<<1, l, m
#define
rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head #define ck(l, x, y, z) a[l]==x&&a[l+1]==y&&a[l+2]==z #define ckk(r, x, y, z) a[r]==x&&a[r-1]==y&&a[r-2]==z const int N = 1e5 + 10; int a[N], tmp[N], n; vector<piii> ans; bool f = false; void flip(int x, int y, int z) { a[x] ^= 1; a[y] ^= 1; a[z] ^= 1; ans.pb({{x, y}, z}); } void fflip(int x, int y) { a[x] ^= 1; a[x+y>>1] ^= 1; a[y] ^= 1; ans.pb({{x, x+y>>1}, y}); } void Flip(int x, int y) { tmp[x] ^= 1; tmp[x+y>>1] ^= 1; tmp[y] ^= 1; //ans.pb({{x, x+y>>1}, y}); } void bruteforce(int l, int r) { vector<pii> vc; for (int i = l; i <= r; i++) { for (int j = i+2; j <= r; j += 2) { vc.pb({i, j}); } } int sz = vc.size(); for (int i = 0; i < (1<<sz); i++) { for (int j = l; j <= r; j++) tmp[j] = a[j]; for (int j = 0; j < sz; j++) { if(i&(1<<j)) { Flip(vc[j].fi, vc[j].se); } } bool ff = true; for (int j = l; j <= r; j++) if(tmp[j]) {ff = false; break;} if(ff) { f = true; for (int j = 0; j < sz; j++) if(i&(1<<j))ans.pb({{vc[j].fi, vc[j].fi + vc[j].se >> 1}, vc[j].se}); return ; } } } void solve(int l, int r) { if(r - l + 1 <= 8) { while(r-l+1 < 8 && l > 1) l--; while(r-l+1 < 8 && r < n) r++; bruteforce(l, r); return ; } if(a[l] == 0) { solve(l+1, r); return ; } if(a[r] == 0) { solve(l, r-1); return ; } if(ck(l, 1, 1, 1)) { flip(l, l+1, l+2); solve(l+3, r); return ; } if(ck(l, 1, 0, 1)) { flip(l, l+2, l+4); solve(l+3, r); return ; } if(ck(l, 1, 0, 0)) { flip(l, l+3, l+6); solve(l+3, r); return ; } if(ckk(r, 1, 1, 1)) { flip(r, r-1, r-2); solve(l, r-3); return ; } if(ckk(r, 1, 0, 1)) { flip(r, r-2, r-4); solve(l, r-3); return ; } if(ckk(r, 1, 0, 0)) { flip(r, r-3, r-6); solve(l, r-3); return ; } if((r-l+1)&1) { fflip(l, r); fflip(l+1, r-1); solve(l+2, r-2); return ; } else { fflip(l, r-1); fflip(l+1, r); solve(l+2, r-2); return ; } } int main() { int cnt = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); solve(1, n); if(f) { printf("YES\n"); printf("%d\n", (int)ans.size()); for (piii p : ans) printf("%d %d %d\n", p.fi.fi, p.fi.se, p.se); } else printf("NO\n"); return 0; }