Topcoder 2016 TCO Algorithm Round 3B Hard

来源:互联网 发布:深圳it 编辑:程序博客网 时间:2024/05/22 03:34

链接:https://community.topcoder.com/stat?c=problem_statement&pm=14379&rd=16798

题意:给一个n个点的图,求团的个数,每个点有一个长度为k<=18的石头剪刀布的字符串,两个点有边当且仅当i的字符串任意循环移位之后和j玩石头剪刀布胜负次数不变

题解:分析A、B之间有边的性质

定义w为3次单位根

将A看成一个多项式,系数这样定:R = 1, S = w, P = w ^ 2①

将B reverse,同样看成一个多项式:R = 1, S = w ^ w, P = w②

求一遍循环卷积,每个位置的系数写成a * w ^ 2 + b * w + c * 1的形式,我们发现a, b, c表示胜\负\平的次数,有边当且仅当最后多项式每个位置都相等

这个不太方便,我们再分析一下,求了两个多项式的点积之后得到的多项式f(x)进行idft之后所有数都相等,注意到idft实际上也算一个代值的过程,即我们带了m个值进去算出来都相等——这证明f(x)是一个常数,即x ^ i(i > 0)系数为0

还有一个性质是,B其实可以直接不变,系数用

假设B = f(x) = ∑a[i] * x ^ i

那么rev(B) = ∑ a[m - 1 - i] * x ^ i, rev(B)系数用②实际上是

∑1 / a[m - 1 - i] * x ^ i = ∑ 1 / (a[m - 1 - i] * x ^ -i) = ∑x ^ (m - 1) / (a[m - 1 - i] * x ^ (m - 1 - i)) = x ^ (m - 1) / f(x)

即dft(rev conj B) = conj dft(B),a[i] * b[i] 和 a[i] * conj(b[i]) 是否为0是一样的

最后就一个简单的状压统计答案即可

#include <bits/stdc++.h>#define xx first#define yy second#define mp make_pair#define pb push_back#define fill(x, y) memset(x, y, sizeof x)#define copy(x, y) memcpy(x, y, sizeof x)using namespace std;typedef long long LL;typedef pair < int, int > pa;typedef complex < double > E;const int MAXN = 100005;const int MAXM = (1 << 18) + 5;const int mod = 1e9 + 7;const double pi = acos(-1);const double eps = 1e-9;int m, f[MAXM], g[MAXM], a = 22222223, b = 12345678, ans = -1;string s[MAXN];E w[20];class RPSRobots{public:int countGoodSet(int n, vector < string > r, int seed, int pR, int pP, int pS){m = r[0].length();for (int i = 0; i < r.size(); i ++) s[i] = r[i];for (int i = r.size(); i < n; i ++)for (int j = 0; j < m; j ++, seed = (1LL * seed * a + b) % mod)if (seed % (pR + pP + pS) < pR) s[i] += "R";else if(seed % (pR + pP + pS) < pR + pP) s[i] += "P";else s[i] += "S";for (int i = 0; i < n; i ++){int cur = 0;for (int j = 0; j < m; j ++)if (s[i][j] == 'R') w[j] = E(1, 0);else if (s[i][j] == 'S') w[j] = E(cos(2 * pi / 3), sin(2 * pi / 3));else w[j] = E(cos(4 * pi / 3), sin(4 * pi / 3));for (int j = 1; j < m; j ++){E ret = 0, wn = E(cos(2 * j * pi / m), sin(2 * j * pi / m));for (int k = 0; k < m; k ++) ret = (ret * wn) + w[k];if (norm(ret) > eps) cur |= 1 << j - 1;}f[cur] ++;}g[0] = 1; for (int i = 0; i < f[0]; i ++) (g[0] <<= 1) %= mod;for (int i = 1; i < 1 << m - 1; i ++) if (f[i])for (int s = (1 << m - 1) - 1 ^ i, j = s; ; j = j - 1 & s){g[i | j] = (1LL * f[i] * g[j] + g[i | j]) % mod;if (!j) break;}for (int i = 0; i < 1 << m - 1; i ++) ans = (ans + g[i]) % mod;return ans;}};


原创粉丝点击