51nod1829 函数

题意:两个集合数量为n,m问第一个集合到第二个集合有多少种合法映射

题解:组合数学的一个模型,n个不同小球装入m个不同的盒子,盒子不为空,答案就是m!*f(n,m),f(n,m)为第二类斯特林数,这里递推会超时,可以考虑容斥,i个盒子为空的方案数为c(m,i)*(m-i)^n然后乘上容斥系数,注意这里的逆元要用O(n)递推,很容易就超时

#include<cstdio>
#define ll long long
using namespace std;
const int maxn=1000005,tt=1e9+7;
ll ji[maxn],ans;
int n,m,p;
ll qsm(ll w,int b){
    ll num=1;
    while(b>0){
        if (b%2==1) num=num*w%tt;
        w=w*w%tt;
        b>>=1;
    }
    return num;
}
ll c(int x,int y){if (x>y) return x;return ji[y]*qsm(ji[x]*ji[y-x]%tt,tt-2)%tt;}
int main(){
    ji[0]=1;for (int i=1;i<=1000000;i++) ji[i]=(ji[i-1]*i)%tt;
    scanf("%d%d",&n,&m);
    p=1;for (int i=m;i>=1;i--) ans=(ans+c(m-i,m)*qsm(i,n)%tt*p%tt+tt)%tt,p=0-p;
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Noevon/p/7955785.html