Statement
给你一个长度为 n 的序列 ai。问有多少 1∼n 的排列 pi,满足 ∀i∈[2..n],有 api−1×api 不为完全平方数。答案对 109+7 取模。
数据范围:n≤300,1≤ai≤109。
Solution
每个数去掉平方因子后,条件等价于没有两个相等的数相邻。
Algorithm 1
把相同的数分类,假设共 m 种不同的数,其中第 i 种有 ci 个。记 f(i,j) 表示填入前 i 种数,有 j 对相同的数相邻的方案数;g(i,j) 表示将第 i 种数拆分成块内块间均有序的 j 块的方案数。下面设 si=∑j=1icj,t=j−(ci−k)+x。
f(i,j)=k=1∑cix=0∑k(xt)⋅(k−xsi−1−t+1)⋅g(i,k)⋅f(i−1,t)g(i,j)=(j−1ci−1)⋅ci!
时间复杂度 O(n3)。
Algorithm 2
考虑容斥,设 f(i) 表示有至少 i 对相等的数相邻的方案数,那么答案为 ∑i=0n−1(−1)i⋅f(i)。
仍然相同的数分类,假设共 m 种不同的数,其中第 i 种有 ci 个。设 g(i,j) 表示在前 i 种数中绑定 j 对数的方案数。
g(i,j)=k=0∑ci−1g(i−1,j−k)⋅(ci−k)!ci!⋅(kci−1)
先假设有顺序,分子是从这 ci−1 个空隙里选择 k 个连起来;分母则是去掉顺序,留到下面在乘排列数。
所以答案为 ∑i=0n−1(−1)i⋅(n−i)!⋅g(m,i)。
时间复杂度 O(n2),可以使用分治 MTT 优化到 O(nlog2n)。
Code
Algorithm 1
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
| #include <bits/stdc++.h> typedef long long LL; const int N = 307, V = 1e9, mod = 1e9 + 7; LL qpow(LL a, int b) { LL s = 1; while(b) { if(b & 1) s = s * a % mod; a = a * a % mod, b >>= 1; } return s; } int n, m = 0, c[N], s[N]; LL fac[N], invf[N], f[N][N], g[N][N], ans = 0; std::vector<int> vec; std::map<int, int> mp; LL C(int n, int m) { return fac[n] * invf[m] % mod * invf[n - m] % mod; } int main() { scanf("%d", &n), fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod; invf[n] = qpow(fac[n], mod - 2); for(int i = n; i; i--) invf[i - 1] = invf[i] * i % mod; for(int i = 2; i * i <= V; i++) vec.emplace_back(i * i); for(int i = 1, x; i <= n; i++) { scanf("%d", &x); for(int y : vec) while(x % y == 0) x /= y; mp[x]++; } for(auto p : mp) c[++m] = p.second, s[m] = s[m - 1] + c[m]; f[0][0] = 1; for(int i = 1; i <= m; i++) for(int k = 1; k <= c[i]; k++) { g[i][k] = C(c[i] - 1, k - 1) * fac[c[i]] % mod; for(int j = 0; j < n; j++) for(int x = 0; x <= k; x++) { int t = j - (c[i] - k) + x; f[i][j] = (f[i][j] + C(t, x) * C(s[i - 1] - t + 1, k - x) % mod * g[i][k] % mod * f[i - 1][t]) % mod; } } return printf("%lld\n", f[m][0]), 0; }
|
Algorithm 2
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
| #include <bits/stdc++.h> typedef long long LL; const int N = 307, V = 1e9, mod = 1e9 + 7; LL qpow(LL a, int b) { LL s = 1; while(b) { if(b & 1) s = s * a % mod; a = a * a % mod, b >>= 1; } return s; } int n, m = 0, c[N]; LL fac[N], invf[N], g[N][N], ans = 0; std::vector<int> vec; std::map<int, int> mp; LL C(int n, int m) { return fac[n] * invf[m] % mod * invf[n - m] % mod; } int main() { scanf("%d", &n), fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % mod; invf[n] = qpow(fac[n], mod - 2); for(int i = n; i; i--) invf[i - 1] = invf[i] * i % mod; for(int i = 2; i * i <= V; i++) vec.emplace_back(i * i); for(int i = 1, x; i <= n; i++) { scanf("%d", &x); for(int y : vec) while(x % y == 0) x /= y; mp[x]++; } for(auto p : mp) c[++m] = p.second; g[0][0] = 1; for(int i = 1; i <= m; i++) for(int j = 0; j < n; j++) for(int k = 0; k < std::min(c[i], j + 1); k++) g[i][j] = (g[i][j] + g[i - 1][j - k] * fac[c[i]] % mod * C(c[i] - 1, k) % mod * invf[c[i] - k]) % mod; for(int i = 0; i < n; i++) ans = (ans + (i & 1 ? -1 : 1) * fac[n - i] * g[m][i]) % mod; return printf("%lld\n", (ans + mod) % mod), 0; }
|