限制相邻元素,求合法序列数。 /** 题目:On the Bench 链接:http://codeforces.com/problemset/problem/840/C 题意:求相邻的元素相乘不为平方数的方案数(这里求得是排列方案数,所以哪怕数相同,只要位置不同也算一种方案) 思路 : 每个数可以表示为 p1^a1 * p2^a2 * ..... 如果 两个数A,B相乘为平方数 则 a1%2 = a1' %2 , a2%2 = a2'%2 ..... 即 对应质因子的幂次 奇偶性相同 这样就可以划分出T组 然后题目就转化为 T种物品 相同种类物品不能放在相邻 求方案数 这题就变成原题 :https://csacademy.com/contest/archive/task/distinct_neighbours/statement/ http://acm.hdu.edu.cn/showproblem.php?pid=6116 做法为dp dp[i][j] 表示插入第 i 组的物品 出现了左右为相同物品的空隙个数为 j 的方案数 那 dp[T][0]*mul 就是最终答案了; mul表示每一组的数都可以排列;哪怕是相同的数由于位置不同,仍然可以排列; 转自:http://www.cnblogs.com/orz010orz/p/7398692.html */ #include<bits/stdc++.h> #define LL long long #define ms(x,y) memset(x,y,sizeof x) #define ls(i) seg[i].lc #define rs(i) seg[i].rc using namespace std; typedef pair<int,int> pii; const int maxn = 305; const int mod = 1e9+7; const LL INF = 1e12 + 10; int cnt[maxn], sum[maxn]; LL dp[maxn][maxn]; LL c[305][305]; int a[maxn], n, m, vis[maxn]; int fac[maxn]; void init(){ c[0][0] = 1; for(int i = 1; i < maxn; i++){ c[i][0] = 1; for(int j = 1; j <= i; j++){ c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod; } } fac[0] = 1; for(int i = 1; i < maxn; i++) fac[i] = (LL)fac[i-1]*i%mod; } bool ok(LL x) { LL lo = 1, hi = 1e9, mi, ans = 0; while(lo<=hi){ mi = (lo+hi)/2; if(mi*mi>=x) hi = mi-1, ans = mi; else lo = mi+1; } return ans*ans==x; } int cmp(int a,int b) { return a>b; } void getCnt() { m = 0; ms(cnt,0); ms(vis,0); for(int i = 1; i <= n; i++){ if(vis[i]) continue; ++m; cnt[m]++; for(int j = i+1; j <= n; j++){ if(vis[j]) continue; ///judge a[i], a[j] is equal? if(ok(1LL*a[i]*a[j])){///judge(i,j) cnt[m]++; vis[j] = 1; } } } } int main() { init(); while(scanf("%d",&n)==1) { for(int i = 1; i <= n; i++){ scanf("%d",&a[i]); } getCnt(); n = m; LL mul = 1; for(int i = 1; i <= n; i++){ sum[i] = sum[i-1]+cnt[i]; mul = mul*fac[cnt[i]]%mod; } ms(dp,0); if(cnt[1]>0) dp[1][cnt[1]-1] = 1; for(int i = 2; i <= n; i++){ for(int j = 0; j <= sum[i]-1; j++){ if(!dp[i-1][j]) continue; for(int k = 1; k <= cnt[i]; k++){ for(int z = 0; z <= k&&z<=j; z++){ LL res = dp[i-1][j]*c[j][z]%mod*c[cnt[i]-1][k-1]%mod*c[sum[i-1]+1-j][k-z]%mod; dp[i][j-z+cnt[i]-k] = (dp[i][j-z+cnt[i]-k]+res)%mod; } } } } cout<<dp[n][0]*mul%mod<<endl; } return 0; }