Description

Gate Of Babylon(bzoj 1272)

Input

Gate Of Babylon(bzoj 1272)

Output

Gate Of Babylon(bzoj 1272)

Sample Input

Gate Of Babylon(bzoj 1272)

Sample Output

12
Gate Of Babylon(bzoj 1272)

HINT

Gate Of Babylon(bzoj 1272)

/*
    容斥+lucas+乘法逆元
    首先,看到有限制的只有15个,因此可以用容斥原理:
    ans=没有限制的方案-有一个超过限制的方案数+有两个超过限制的方案数-有三个超过限制的方案数....
    
    对于无限制的方案,从n组数中选m个的方案数为C(n+m-1,m)。 
    有一个超过限制直接用总数减去(这个的限制+1)就是当前的总数,相当于强制要选限制+1个,其他任意。。。
    要求不超过m的方案数,也就是ΣC(n+i-1,i)(0<=i<=m)=C(n+m,m)
    
    然后用lucas定理。 
*/
#include<iostream>
#include<cstdio>
#define N 100010
#define lon long long
using namespace std;
lon inv[N],jc1[N],jc2[N],ans;
int n,t,m,mod,b[20];
void init(){
    inv[0]=inv[1]=1;for(int i=2;i<=mod;i++) inv[i]=((mod-mod/i)*inv[mod%i])%mod;
    jc1[0]=1;for(int i=1;i<=mod;i++) jc1[i]=(jc1[i-1]*i)%mod;
    jc2[0]=1;for(int i=1;i<=mod;i++) jc2[i]=(jc2[i-1]*inv[i])%mod;
}
lon C(int n,int m){
    if(n<m) return 0;
    if(n>mod||m>mod) return (C(n%mod,m%mod)*C(n/mod,m/mod))%mod;
    else return ((jc1[n]*jc2[m])%mod)*jc2[n-m]%mod;
}
void dfs(int now,int x,int w){
    if(now>t){
        ans=(ans+x*C(m+n-w,m-w))%mod;
        return;
    }
    dfs(now+1,-x,w+b[now]+1);
    dfs(now+1,x,w);
}
int main(){
    scanf("%d%d%d%d",&n,&t,&m,&mod);
    for(int i=1;i<=t;i++) scanf("%d",&b[i]);
    init();
    dfs(1,1,0);
    cout<<(ans%mod+mod)%mod;
    return 0;
}

 

相关文章: