• Codeforces 830C On the Bench


    题意:给你n个数,问有多少种排列方式使得任意两个相邻的数的乘积都不是完全平方数

    我好弱,被组合和数论吊着打。。。

    首先我们可以把每个数中固有的完全平方数给分离出来,那么答案其实就只与处理后的序列相关。

    考虑把相同的数分为一类,设dp[i][k]表示前i组数分为k类的方案数,于是用隔板法搞搞就有:

    $dp[i][j]=sum_{k=1}^{j}{dp[i][j-k]}C^{k-1}_{n_{i}-1}*frac{n_{i}!}{k!}$

    根据容斥原理,最终的答案就是:

    $ans=dp[n]n!−dp[n−1]!(n-1)!+⋯+(−1)^{(n−i)}dp[i]i!$

    之后注意一下阶乘的求逆即可

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 300+10
    #define MODD 1000000007
    #define fi first
    #define se second
    typedef long long LL;
    int n;
    LL jie[MAXN],c[MAXN][MAXN],dp[MAXN][MAXN]; 
    map<LL,int>cnt;
    LL pw(LL a,LL b){
        a%=MODD;
        LL ans=1;
        for(;b;b>>=1,a=a*a%MODD)
            if(b&1)ans*=a,ans%=MODD;
        return ans;    
    }
    void init(){
        c[0][0]=jie[0]=1;
        for(int i=1;i<=300;i++){
            c[i][0]=1;
            for(int j=1;j<=300;j++)
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%MODD;    
        }
        for(int i=1;i<=300;i++)jie[i]=jie[i-1]*i%MODD;
    }
    int main(){
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            LL x;
            scanf("%I64d",&x);
            for(int j=2;j*j<=x;j++)
                while(x%(j*j)==0)x/=(j*j);
            cnt[x]++;    
        }
        dp[0][0]=1;
        map<LL,int>::iterator it;
        int tot=1;
        for(it=cnt.begin();it!=cnt.end();it++){
            for(int i=1;i<=n;i++){
                int m=min(it->se,i);
                for(int j=1;j<=m;j++){
                    LL tmp=jie[it->se];    
                    tmp*=c[(it->se)-1][j-1];tmp%=MODD;
                    tmp*=pw(jie[j],MODD-2);tmp%=MODD;
                    dp[tot][i]+=dp[tot-1][i-j]*tmp;
                    dp[tot][i]%=MODD;
                }    
            }
            tot++;
        }
        tot--;    
        LL ans=dp[tot][n]*jie[n]%MODD;
        int flag=0;
        for(int i=n-1;i>=0;i--){
            if(flag&1)ans=(ans+dp[tot][i]*jie[i])%MODD;
            else ans=(ans-dp[tot][i]*jie[i]+MODD)%MODD;
            ans=(ans+MODD)%MODD;
            flag^=1;
        }
        printf("%I64d
    ",ans);
        return 0;
    }
  • 相关阅读:
    thinkphp 模板文件
    thinkphp 目录安全文件
    thinkphp 防止sql注入
    thinkphp 表单令牌
    thinkphp 表单合法性检测
    thinkphp 输入过滤
    thinkphp 静态缓存
    thinkphp sql解析缓存
    thinkphp 查询缓存
    thinkphp 快速缓存
  • 原文地址:https://www.cnblogs.com/NINGLONG/p/7716049.html
Copyright © 2020-2023  润新知