[BZOJ1659][Usaco2006 Mar]Lights Out 关灯
[BZOJ1659][Usaco2006 Mar]Lights Out 关灯
试题描述
奶牛们喜欢在黑暗中睡觉。每天晚上,他们的牲口棚有L(3<=L<=50)盏灯,他们想让亮着的灯尽可能的少。他们知道按钮开关的位置,但喜闻乐见的是他们并没有手指。你得到了一个长度为T(1<=T<=7)的插槽用以帮助奶牛们改变灯的状态。
输入
第一行,两个整数L和T。第二行给出一个长度为L的01串表示初始灯的状态,0表示灯是灭的,1表示灯是亮的。第三行给出一个长度为T的01串,表示你获得的插槽。
输出
第一行输出一个整数K,表示在满足亮着的灯最少的情况下,你要用插槽操作的次数。第二行到第K+1行,每行一个整数表示你的插槽使用的位置。
"K最小的解,并且满足解的字典序最大(即按钮开关的位置尽可能靠后)"
输入示例
10 4 1111111111 1101
输出示例
5 1 3 4 6 7
数据规模及约定
见“试题描述”
题解
暴力大 dp,设 f(i, S) 表示考虑是否在第 i 个位置使用插槽,分为两个转移。根据当前的 S 推第 i-1 个位置的状态,更新当前的答案。
再记一下方案,使其步数最小且字典序最大。
然后使劲写就行了,范围小随便写。
下面是代码,估计没人想看。。。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); } return x * f; } #define maxn 55 #define maxm 10 #define maxst 130 #define oo 147483647 #define LL long long int n, m, Lig[maxn], Swi[maxm], f[maxn][maxst], g[maxn][maxst][maxn], cg[maxn][maxst]; int bin[maxm], cb; void Bin(int s) { cb = 0; while(s) { bin[++cb] = (s & 1); s >>= 1; } for(int i = cb; i; i--) printf("%d", bin[i]); if(!cb) putchar('0'); return ; } int _s, _l; LL ls[maxn]; int lit(int a, int b) { return ls[b] - (ls[a-1] << b-a+1); } int cntl(int t, int n) { int ans = 0; for(int i = 1; i <= n; i++) { if(!(t & 1)) ans++; t >>= 1; } return ans; } bool larger(int i, int j, int a, int b) { if(cg[i][j] != cg[a][b]) return cg[i][j] < cg[a][b]; int c = cg[i][j]; for(int k = 1; k <= c; k++) if(g[i][j][k] != g[a][b][k]) return g[i][j][k] > g[a][b][k]; return 0; } int main() { read(); read(); char tc = Getchar(); while(!isdigit(tc)) tc = Getchar(); while(isdigit(tc)) { Lig[++n] = tc - '0'; tc = Getchar(); } while(!isdigit(tc)) tc = Getchar(); int cnt = 0, _c = 0; while(isdigit(tc)) { Swi[++m] = tc - '0'; _s = _s << 1 | Swi[m]; _l = _l << 1 | Lig[m]; cnt += (Lig[m] ^ 1); _c += (Lig[m] ^ Swi[m] ^ 1); tc = Getchar(); } int all = (1 << m) - 1; for(int S = 0; S <= all; S++) f[1][S] = -oo; f[1][_l] = cnt; f[1][_l^_s] = _c; cg[1][_l^_s] = 1; g[1][_l^_s][1] = 1; for(int i = 1; i <= n; i++) ls[i] = ls[i-1] << 1 | Lig[i]; for(int i = 2; i <= n - m + 1; i++) for(int S = 0; S <= all; S++) { f[i][S] = -oo; for(int t = 0; t <= 1; t++) { int SS = (t << m-1) | (S >> 1); // printf("%d ", i-1); Bin(SS); putchar(' '); printf("%d\t", f[i-1][SS]); if((S & 1) == Lig[i+m-1]) { int tmp = f[i-1][SS] + (Lig[i+m-1] ^ 1); if(tmp > f[i][S]) { f[i][S] = tmp; cg[i][S] = cg[i-1][SS]; for(int k = 1; k <= cg[i][S]; k++) g[i][S][k] = g[i-1][SS][k]; } else if(tmp == f[i][S] && larger(i-1, SS, i, S)) { cg[i][S] = cg[i-1][SS]; for(int k = 1; k <= cg[i][S]; k++) g[i][S][k] = g[i-1][SS][k]; } } SS = (t << m-1) | ((S ^ _s) >> 1); // printf("%d ", i-1); Bin(SS); putchar(' '); printf("%d\t", f[i-1][SS]); if((S & 1) == (Lig[i+m-1] ^ Swi[m])) { int tmp = f[i-1][SS] - cntl((S ^ _s) >> 1, m-1) + cntl(S, m); if(tmp > f[i][S]) { f[i][S] = tmp; cg[i][S] = cg[i-1][SS]; for(int k = 1; k <= cg[i][S]; k++) g[i][S][k] = g[i-1][SS][k]; g[i][S][++cg[i][S]] = i; } else if(tmp == f[i][S]) { g[i-1][SS][++cg[i-1][SS]] = i; if(larger(i-1, SS, i, S)) { cg[i][S] = cg[i-1][SS]; cg[i-1][SS]--; for(int k = 1; k <= cg[i][S]; k++) g[i][S][k] = g[i-1][SS][k]; } } } // printf("%d ", i); Bin(S); putchar(' '); printf("%d\n", f[i][S]); } } for(int S = 0; S <= all; S++) { if(f[maxn-1][maxst-1] < f[n-m+1][S]) { f[maxn-1][maxst-1] = f[n-m+1][S]; cg[maxn-1][maxst-1] = cg[n-m+1][S]; for(int k = 1; k <= cg[maxn-1][maxst-1]; k++) g[maxn-1][maxst-1][k] = g[n-m+1][S][k]; } else if(f[maxn-1][maxst-1] == f[n-m+1][S] && larger(n-m+1, S, maxn-1, maxst-1)) { cg[maxn-1][maxst-1] = cg[n-m+1][S]; for(int k = 1; k <= cg[maxn-1][maxst-1]; k++) g[maxn-1][maxst-1][k] = g[n-m+1][S][k]; } } // printf("%d\n", f[maxn-1][maxst-1]); printf("%d\n", cg[maxn-1][maxst-1]); for(int i = 1; i <= cg[maxn-1][maxst-1]; i++) printf("%d\n", g[maxn-1][maxst-1][i]); return 0; }