topcoder srm 710 div1
problem1 link
给定两个长度都为$n$的数组$A,B$,给出一个操作序列将$A$变成$B$。每个操作可以是以下两种之一:(1)选择一个$i,0\leq i <n$且$A_{i} \neq 0$,令$t=A_{i}$,然后置$A_{i}=0$,最后令$i$位置后的连续$t$个位置分别加1。这个是循环的,$n-1$之后是位置$0$。可能有些位置最后增加的值会超过1;(2)选择一个$i,0\leq i <n$且$A_{i} \neq 0$,然后从$i$开始(包括$i$)向前,每个位置的数字减去1,直到一个位置是$0$,然后把刚刚减去的值的和加到这个位置上。
可以看出操作(2)是操作(1)的逆操作。可以先将$A$只使用操作(1)变成除了$A_{0}$外其余位置都是0,$B$也这样操作,操作序列分别为$P,Q$,那么$P$加上$Q$的逆操作就是答案。
problem2 link
https://blog.csdn.net/xyyxyyx/article/details/102505744#antiNim_41
http://makaidong.com/Saurus/18221_5909731.html
(1)全是1(不包含魔力堆):
如果全是1,那么无论有几堆,先手都是必胜的. 因为如果有奇数个1,那么Alice直接拿掉魔力石子,然后选择改变游戏,那么他还是赢的.如果有偶数个1,那么Alice直接拿掉魔力石子,然后不选择改变游戏,于是他还是赢的。
(2)不全是1:
anti-nim的先手必胜条件(不考虑多魔法石子):
i SG为0,且所有石子均为1
ii SG不为0,且存在一堆石子大于1
所以,如果不全是1,且SG为0的话,Alice是必输的,因为他取魔力石子后,仍然无法改变必输的情况
所以现在情况只有不全是1,且SG不为0. 注意到这个时候任何一方如果直接取魔力石子,都是必败的.所以双方应该会保持SG不为0,然后进行对峙
首先考虑所以石子的数量不超过3.那么SG函数的值就只有3个,1,2,3. 当SG为1或3的时候,肯定有一种取法使得SG为2. 而SG为2的最终情况是2附加一个魔力石子,这种情况是必败的. 所以当石子的数量不超过3时,SG=2先手必败,反之必胜
接下来考虑石子的数量超过3,也就是有4和4以上的数.那么SG函数的值可以分成1和超过1的那些情况. 如果当前SG值为1,那么只能把它变成超过1的值,然而对手又可以把它变回到1
我们考虑假设只有1个超过3的数,那么这时候SG值肯定是大于3的. 直接改变这个数,我们可以使得接下来的局面变成SG=2. 也就是说,如果只有1个超过3的数,那么就是先手必胜
那么如果SG值为1,且我们知道存在超过3的数,那么超过3的数的数量必定至少有2个. 也就是说,经过不断地对峙,原来SG值为1的话,现在SG值仍然为1. 但是经过了很多减少,一定会达到这个局面. 即SG值为1,且超过3的数量只有2个
当这2个其中的一个数减到4以下时,就变成了只有1个超过3的数, 即SG->1->3->2(最终结果).也就是说SG如果为1,必定会转化成2,那么SG=1就是必败局面,而其他情况是必胜局面
最后结论就是: 如果有大于3的数,那么SG=1必败; 如果没有,那么SG=2必败
problem3 link
令$T=\frac{m(m-1)}{2}$.表示有 這麼多個二元組$(i,j), 0\leq i<j<m$
計算這樣一個大小爲$2^T$的數組,$f[0],f[1],.., f[2^{T}-1]$.其中$f[i]$表示在一維空間中選出$m$個區間,使得$i$中爲1的那些bit對應的二元組相交的情況有多少種.
每一個區間看作一對匹配的括號.首先枚舉有多少種不同的括號(不同的兩個不完全重合).
比如對於2種不同括號的有五種形狀:
\begin{matrix}
( & &) & & (& &) & & (& & &) & & (&) & & ( &) & & \\
& (& &) & & (&) & & & (&) & & & & (&) & (& &) &
\end{matrix}
前後兩個滿足$L_{1}<L_{2}$或者$L_{1}<=L_{2}, R_{1}<R_{2}$, 以避免重復搜索
然後對於$m$個區間枚舉每個區間屬於哪一種種類的括號.
有了這個$f$數組之後, 對於$k$維的問題,就是求解$f_{new}[i]=\sum_{j\&k=i}f_{old}[j]f_{old}[k]$這樣一個dp, 重復計算$k$次就行. 這個可以用Fast Walsh Hadamard.
https://codeforces.com/blog/entry/50572
https://blog.csdn.net/zxyoi_dreamer/article/details/100515338
https://www.cnblogs.com/y-clever/p/6875743.html
https://www.bbsmax.com/A/qVdewO1QJP/
code for problem1
#include <vector> class ReverseMancala { public: std::vector<int> findMoves(const std::vector<int> &S, const std::vector<int> &T) { auto p = get(S, false); auto q = get(T, true); std::copy(q.rbegin(), q.rend(), std::back_inserter(p)); return p; } private: std::vector<int> get(std::vector<int> s, bool tag) { int sum = 0; int n = static_cast<int>(s.size()); for (int i = 0; i < n; ++i) { sum += s[i]; } std::vector<int> ans; while (s[0] != sum) { int p = 1; while (!s[p]) { ++p; } if (!tag) { ans.push_back(p); } else { ans.push_back((p + s[p]) % n + n); } int cur = s[p]; s[p] = 0; for (int i = 0; i < cur; ++i) { ++s[(p + 1 + i) % n]; } } return ans; } };
code for problem2
#include <algorithm> #include <string> #include <vector> class MagicNim { public: std::string findWinner(const std::vector<int> &a) { int sg = 0; int m = 0; for (int x : a) { sg ^= x; m = std::max(m, x); } if (m >= 4) { return sg == 1 ? "Bob" : "Alice"; } else { return sg == 2 ? "Bob" : "Alice"; } } };
code for problem3
#include <vector> class Hyperboxes { public: int findCount(int n, int m, int k) { this->m = m; c.resize(m * 2 + 1); c[0] = 1; for (int i = 1; i <= m * 2; ++i) { c[i] = Mul(c[i - 1], n - i + 1); c[i] = Mul(c[i], Pow(i, kMod - 2)); } int total = m * (m - 1) / 2; int S = 1 << total; g.resize(S, 0); f.resize(S, 0); for (int cur = 1; cur <= m; ++cur) { for (auto &e : g) { e = 0; } std::vector<int> visited(m, 0); std::vector<std::pair<int, int>> group_and_pos(m * 2); std::vector<int> group(m); Dfs1(0, -1, cur, &group_and_pos, 0); Dfs2(0, cur, &group, &visited); } for (int i = 1; i < S; i <<= 1) { for (int j = 0; j < S; j += i << 1) { for (int k = 0; k < i; ++k) { f[j + k] = Add(f[j + k], f[i + j + k]); } } } for (int i = 0; i < S; ++i) { f[i] = Pow(f[i], k); } for (int i = 1; i < S; i <<= 1) { for (int j = 0; j < S; j += i << 1) { for (int k = 0; k < i; ++k) { f[j + k] = Sub(f[j + k], f[i + j + k]); } } } return f[0]; } private: int Index(int i, int j, int m) { if (i > j) { std::swap(i, j); } int pre = i == 0 ? 0 : (m - 1 + m - i) * i / 2; return pre + (j - i - 1); } int Add(int a, int b) { a += b; if (a >= kMod) { a -= kMod; } return a; } int Sub(int a, int b) { a -= b; if (a < 0) { a += kMod; } return a; } int Mul(int a, int b) { long long la = a; return static_cast<int>(la * b % kMod); } int Pow(int a, int b) { long long la = a; long long r = 1; while (b > 0) { if ((b & 1) == 1) { r = r * la % kMod; } la = la * la % kMod; b >>= 1; } return static_cast<int>(r); } void Dfs1(int cur, int gcnt, int gnum, std::vector<std::pair<int, int>> *group, int mask) { if (cur == 2 * gnum) { std::vector<int> left(m); std::vector<int> right(m); for (int i = 0; i < 2 * gnum; ++i) { const auto &e = group->at(i); if (e.first < gnum) { left[e.first] = e.second; } else { right[e.first - gnum] = e.second; } } for (int i = 0; i < gnum; ++i) { if (left[i] == right[i]) { return; } } for (int i = 0; i < gnum; ++i) { for (int j = i + 1; j < gnum; ++j) { if (left[i] == left[j] && right[i] >= right[j]) { return; } } } int st = 0; for (int i = 0; i < gnum; ++i) for (int j = i + 1; j < gnum; ++j) if (right[i] >= left[j]) st |= 1 << Index(i, j, gnum); g[st] = Add(g[st], c[gcnt + 1]); return; } auto &e = group->at(cur); for (int i = 0; i < gnum; ++i) { if ((mask & (1 << i)) != 0) { continue; } e.first = i; mask |= 1 << i; e.second = gcnt + 1; Dfs1(cur + 1, gcnt + 1, gnum, group, mask); if (cur && e.first > group->at(cur - 1).first) { e.second = gcnt; Dfs1(cur + 1, gcnt, gnum, group, mask); } mask ^= 1 << i; break; } for (int i = 0; i < gnum; ++i) { if ((mask & (1 << i)) != 0 && (mask & (1 << (i + gnum))) == 0) { e.first = i + gnum; mask |= 1 << (i + gnum); e.second = gcnt + 1; Dfs1(cur + 1, gcnt + 1, gnum, group, mask); if (cur && e.first > group->at(cur - 1).first) { e.second = gcnt; Dfs1(cur + 1, gcnt, gnum, group, mask); } mask ^= 1 << (i + gnum); } } } void Dfs2(int cur, int gnum, std::vector<int> *group, std::vector<int> *visited) { if (cur == m) { for (int i = 0; i < gnum; ++i) { if (visited->at(i) == 0) { return; } } int total = gnum * (gnum - 1) / 2; for (int s = 0; s < (1 << total); ++s) { if (g[s] == 0) { continue; } int st = 0; for (int i = 0; i < m; ++i) { for (int j = i + 1; j < m; ++j) { if (group->at(i) == group->at(j) || (s & (1 << Index(group->at(i), group->at(j), gnum)))) { st |= 1 << Index(i, j, m); } } } f[st] = Add(f[st], g[s]); } return; } for (int j = 0; j < gnum; ++j) { group->at(cur) = j; visited->at(j) += 1; Dfs2(cur + 1, gnum, group, visited); visited->at(j) -= 1; } } static constexpr int kMod = 998244353; int m; std::vector<int> c; std::vector<int> g; std::vector<int> f; };