codeforces 429 On the Bench dp+排列组合 限制相邻元素,求合法序列数。

限制相邻元素,求合法序列数。
/**
题目: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;
}
原文地址:https://www.cnblogs.com/xiaochaoqun/p/7419091.html