Codeforces 840C On the Bench dp
两个数如果所有质因子的奇偶性相同则是同一个数,问题就变成了给你n个数, 相同数字不能相邻的方案数。
dp[ i ][ j ]表示前 i 种数字已经处理完, 还有 j 个位置需要隔开的方案数。
转移的话, 我们枚举第i + 1种数字分成的段数, 然后枚举有几段插到 j 个空格里面, 然后转移。
最后乘上各种数字个数的阶乘。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 300 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} int n, cnt, a[N], c[N]; int g[N][N], sum[N]; int dp[N][N]; ull hs[N]; map<int, int> Map; vector<ull> oo; int F[N], Finv[N], inv[N]; void init() { inv[1] = F[0] = Finv[0] = 1; for(int i = 2; i < N; i++) inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod; for(int i = 1; i < N; i++) F[i] = 1LL * F[i - 1] * i % mod; for(int i = 1; i < N; i++) Finv[i] = 1LL * Finv[i - 1] * inv[i] % mod; } int comb(int n, int m) { if(n < 0 || n < m) return 0; return 1LL * F[n] * Finv[m] % mod * Finv[n - m] % mod; } int main() { init(); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); Map.clear(); for(int j = 2; j * j <= a[i]; j++) { if(a[i] % j) continue; while(a[i] % j == 0) { Map[j]++; a[i] /= j; } } if(a[i] > 1) Map[a[i]]++; for(auto& t : Map) { if(t.se & 1) { hs[i] *= 23333; hs[i] += t.fi; } } oo.push_back(hs[i]); } sort(ALL(oo)); oo.erase(unique(ALL(oo)), oo.end()); for(int i = 1; i <= n; i++) a[i] = lower_bound(ALL(oo), hs[i]) - oo.begin() + 1; for(int i = 1; i <= n; i++) c[a[i]]++; cnt = n; n = SZ(oo); for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + c[i]; g[0][0] = 1; for(int i = 0; i <= cnt; i++) { for(int j = 0; j <= cnt; j++) { if(!g[i][j]) continue; for(int k = 1; i + k <= cnt; k++) { add(g[i + k][j + 1], g[i][j]); } } } dp[1][c[1] - 1] = 1; for(int i = 1; i < n; i++) { for(int j = 0; j <= cnt; j++) { if(!dp[i][j]) continue; int num = c[i + 1]; for(int k = 1; k <= num && k <= sum[i] + 1; k++) { int way = g[num][k]; for(int z = max(0, k - sum[i] - 1 + j); z <= k; z++) { add(dp[i + 1][j - z + num - k], 1LL * way * comb(j, z) % mod * comb(sum[i] + 1 - j, k - z) % mod * dp[i][j] % mod); } } } } int ans = dp[n][0]; for(int i = 1; i <= n; i++) ans = 1LL * ans * F[c[i]] % mod; printf("%d\n", ans); return 0; } /* */