• 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;
    }
  • 相关阅读:
    Button 使用Command 按钮置灰未更新
    C# TextBox 焦点
    MultiTigger 绑定异常处理
    C# 获取程序路径
    Linux 权限设置chmod
    WPF SpreadSheetGear电子表单
    WPF 窗口
    Excel公式 提取文件路径后缀
    C#/VB.NET 获取电脑属性(硬盘ID、硬盘容量、Cpu序列号、MAC地址、系统类型)
    DevExpress Carousel 设置水平滑动列表
  • 原文地址:https://www.cnblogs.com/NINGLONG/p/7716049.html
Copyright © 2020-2023  润新知