Description
给定正整数 N,和两个长为 N 的 01 序列 a 和 b。定义一次操作为:
- 将 b 序列中的一个值翻转(即 0 变成 1,1 变成 0,下同)。
- 对于 b 序列中每个值为 1 的位置,将 a 序列中对应位置的值翻转。
- 将 b 序列向右循环移位 1 位。即若当前 b 序列为 b1b2⋯bn,则接下来变为 bnb1b2⋯bn−1。
有 T 次询问,对每一次询问,你需要回答出至少需要几次操作,才能使 a 序列中每一个位置的值都变为 0。
link
Solution
显然可以把 a,b 数组看成两个数,操作一就是对 b 的某一位取反,操作二就是让 a 异或 b,操作三是让 b←⌊2b⌋。
容易发现操作数不超过 3n,因为可以先用至多 n 次操作把 b 变成 0。然后每连续两次操作就让 b 的某一位变成 1,把 a 的这一位消掉,然后 b 清空。
然而这样做是 O(T⋅nn) 的,过不了且没法优化。
观察可知,如果第 i 次操作将第 j 位异或 1,总共进行 s 次操作,那么这次操作对最终 a 的贡献就是 j∼j+s−i 这些位取反(在模 n 意义下)。
这样就可以 dp 了。
设 fi,j 表示进行恰好 i 次操作,能否让 a 变成 j,设 x 为任意一个模 n 意义下连续的长度为 1 的数组所对应的状态,那么就让 fi,j←fi−1,j⊕x⊕b。
初始 f0,a=1,时间复杂度:O(T⋅n⋅2n),过不了。
考虑把操作一的贡献和操作二、三的贡献拆开算。操作一所做的贡献就相当于初始 b=0 进行若干次操作对 a 的贡献,显然可以预处理,即设 fi,j 表示 b 初始值为 0,对 a 能否做出 j 的贡献。
设 x 为任意一个模 n 意义下连续的长度为 1 的数组所对应的状态,那么就让 fi,j←fi−1,j⊕x。
而操作二、三就是对 b 进行这么多操作的异或和,枚举操作次数即可求得。
时间复杂度:O(n2⋅2n+Tn)。
具体实现细节见代码
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <cstdio> #include <iostream> #include <map>
int n, a, b; int f[100][1 << 20];
int shift(int x) { return (x >> 1) + (1 << n - 1) * (x & 1); }
int tonum(std::string s) { int ret = 0; for (int i = 0; i < static_cast<int>(s.size()); ++i) ret = (ret << 1) + s[i] - '0'; return ret; }
int calc(int a, int b) { for (int i = 0; i <= 3 * n; ++i, b = shift(b)) { if (f[i][a]) return i; a ^= b; } return -1; }
void prework() { f[0][0] = 1; for (int i = 1; i <= 3 * n; ++i) { int s = (1 << ((i - 1) % n + 1)) - 1; for (int j = 0; j < n; ++j, s = shift(s)) { for (int k = 0; k < (1 << n); ++k) f[i][k] |= f[i - 1][k ^ s]; } } }
void dickdreamer() { int t; std::cin >> t >> n; prework(); for (; t; --t) { std::string s, t; std::cin >> s >> t; a = tonum(s), b = tonum(t); std::cout << calc(a, b) << '\n'; } }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; while (T--) dickdreamer(); return 0; }
|