hdu6143 排列组合

版权声明:编写不易,转载请注明出处,谢谢。 https://blog.csdn.net/WilliamSun0122/article/details/77340605

题意
一个人的名字有名和姓,名和姓上各有n个字符位置,每个位置的字符从m个字符里面选择。问你有多少个人的名字其名和姓上没有相同的字符。

题解
比赛的时候排列组合了半天,差点没写出来。官方题解是用容斥写的,有兴趣的可以看看别人容斥的博客。
当时比赛的时候我正着写和反着写都没写出来,最后正着里面套反写出来了。

ans=C1m1n(m1)n+C2m(2nC121)(m2)n+...
解释一下公式(我是把名和姓分开考虑)
答案=(名里面出现一个字符)*(名里面出现一个字符的种数)*(姓里面n个位置全部是m-1个字符中的一个的种数)+(名里面出现两个字符)*(名里面n个位置全部是2个字符中的一个的种数-从2个字符中选择一个*名里面全部是一个字符的种数)*(姓里面n个位置全部是m-2个字符中的一个的种数)+…

上面的公式我总体上是直接正着求名和姓中没有相同字符的名字,但是再求名里面出现n个字符的种数(这里的意思是名里面选出的n个字符必须至少出现一次)的时候我是反着求的,就是先求出n个字符去组成名的总数( 2n )-从n个字符中选出n-1个字符去组成名的种数( Cn1nf[n1] )-…-从n个字符中选出1个字符去组成名的种数( C1nf[1] )。
这里的f[i]代表i个字符组成名(这i个字符里面每一个至少出现一次)
f[i]的求解是递推的。

大家把解释结合公式看,要是还不懂可以看看代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2005;
const int mod = 1e9+7;
ll c[maxn][maxn],n,m,f[maxn];

ll pow_mod(ll a,ll b)//快速幂
{
    ll res = 1;
    while(b)
    {
        if(b&1) res = (res*a)%mod;
        a = (a*a)%mod;
        b>>=1;
    }
    return res;
}

void init()//组合数
{
    for(int i=0;i<maxn;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(j==0 || j==i) c[i][j]=1;
            else c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
}

int main()
{
    int t;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        ll ans=0;
        for(int i=1;i<=min(n,m);i++)
        {
            if(i==1)
            {
                f[1]=1;
                ll res = (c[m][1]*pow_mod(m-1,n))%mod;
                ans += res;
                ans %= mod;
            }
            else
            {
                ll res = (c[m][i]*pow_mod(m-i,n))%mod;
                ll tmp = 0;
                for(int j=1;j<i;j++)//递推求解f[i]
                {
                    tmp += (c[i][j]*f[j])%mod;
                    tmp %= mod;
                }
                f[i] = pow_mod(i,n)-tmp;
                res *= f[i];
                res %= mod;
                ans += res;
                ans %= mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/WilliamSun0122/article/details/77340605