首页 > 其他 > 详细

Killer Names

时间:2019-08-29 12:52:43      阅读:73      评论:0      收藏:0      [点我收藏+]

HDU

题意:姓名由姓和名两部分组成,每个部分都含有n个字符,现在一共有m个字符,求姓和名不含相同字符的姓名数量.\((n,m<=2000)\)

分析:我们只要确定了姓的组成,就能求出名的组成方案数.所以我们设\(f[i]\)表示姓的n个字符由i个不同的字符组成的方案数.运用容斥的思想,用总方案数(n个字符由i个字符组成的方案数)减去包含相同字符的方案数,就可以得到\(f[i]\)的表达式了.

\(f[i]=i^n-\sum_{j=1}^{i-1}f[j]*C_i^j\)

得到了\(f[i]\),也就是姓的组成方案,就很容易得到名的组成方案数.\(ans=\sum_{i=1}^{min(n,m)}f[i]*C_m^i*(m-i)^n\).解释一下这个式子,\(f[i]*C_m^i\)计算的是姓的方案数,剩下的\((m-i)\)个字符构成名的时候可以随便填,就是\((m-i)^n\).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=2005;
const int mod=1e9+7;
ll jc[N],inv[N],f[N];
inline int ksm(int a,int b){
    int cnt=1;
    while(b){
        if(b&1)cnt=(1ll*cnt*a)%mod;
        a=(1ll*a*a)%mod;
        b>>=1;
    }
    return cnt;
}
inline int C(int n,int m){return ((1ll*jc[n]*inv[n-m])%mod*inv[m])%mod;}
int main(){
    jc[0]=1;for(int i=1;i<=2000;++i)jc[i]=(1ll*jc[i-1]*i)%mod;
    inv[2000]=ksm(jc[2000],mod-2);for(int i=2000-1;i>=0;--i)inv[i]=(1ll*inv[i+1]*(i+1))%mod;//预处理阶乘和逆元
    int T=read();
    while(T--){
        int n=read(),m=read();
        for(int i=1;i<=m;++i){
            f[i]=ksm(i,n);
            for(int j=1;j<=i-1;++j)
                f[i]=(f[i]-(1ll*f[j]*C(i,j)%mod)+mod)%mod;//这里一定要加mod,因为可能会减成负数
        }//计算f[i]
        ll ans=0;
        for(int i=1;i<=min(m,n);++i)
            ans=(ans+(1ll*f[i]*C(m,i)%mod*ksm(m-i,n))%mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

Killer Names

原文:https://www.cnblogs.com/PPXppx/p/11428585.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!