题意:有$N$种物品,其中$T$个物品有限定数量$B_i$,其他则没有限定。问从中取出不超过$M$个物品的方案数,对质数$P$取模。$N,M \leq 10^9 , T \leq 15 , P \leq 10^5$
在$N$种物品中选出不超过$M$中物品的方案数可以用插板法(插板法只能满足刚好$M$个,那么我们可以虚构出一个数量无限的物品,把剩下的没选择完的都丢给它,这样插板法就能做了)
发现$T$很小,直接容斥即可
$N,M \leq 10^9$不能直接预处理,考虑到$P$为质数且范围较小,可以直接使用$Lucas$定理
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 inline int read(){ 5 int a = 0; 6 bool f = 0; 7 char c = getchar(); 8 while(c != EOF && !isdigit(c)){ 9 if(c == ‘-‘) 10 f = 1; 11 c = getchar(); 12 } 13 while(c != EOF && isdigit(c)){ 14 a = (a << 3) + (a << 1) + (c ^ ‘0‘); 15 c = getchar(); 16 } 17 return f ? -a : a; 18 } 19 20 const int MAXN = 100000; 21 int N , M , P , Q , jc[MAXN + 10] , ny[MAXN + 10] , B[16] , ans; 22 23 inline int poww(long long a , int b){ 24 int times = 1; 25 while(b){ 26 if(b & 1) 27 times = times * a % Q; 28 a = a * a % Q; 29 b >>= 1; 30 } 31 return times; 32 } 33 34 inline int C(int N , int M){ 35 if(N < 0 || M < 0 || N < M) 36 return 0; 37 return 1ll * jc[N] * ny[M] % Q * ny[N - M] % Q; 38 } 39 40 int lucas(int N , int M){ 41 if(N + M == 0) 42 return 1; 43 return 1ll * C(N % Q , M % Q) * lucas(N / Q , M / Q) % Q; 44 } 45 46 void choose(int now , int num , int cnt){ 47 if(num < 0) 48 return; 49 if(now > M) 50 ans = (ans + (cnt & 1 ? -1ll : 1ll) * lucas(num + N , N) + Q) % Q; 51 else{ 52 choose(now + 1 , num , cnt); 53 choose(now + 1 , num - B[now] - 1 , cnt + 1); 54 } 55 } 56 57 int main(){ 58 #ifdef LG 59 freopen("4640.in" , "r" , stdin); 60 #endif 61 N = read(); 62 M = read(); 63 P = read(); 64 Q = read(); 65 jc[0] = ny[0] = 1; 66 for(long long i = 1 ; i < Q ; i++) 67 jc[i] = jc[i - 1] * i % Q; 68 ny[Q - 1] = poww(jc[Q - 1] , Q - 2); 69 for(long long i = Q - 2 ; i ; i--) 70 ny[i] = ny[i + 1] * (i + 1) % Q; 71 for(int i = 1 ; i <= M ; i++) 72 B[i] = read(); 73 choose(1 , P , 0); 74 cout << ans; 75 return 0; 76 }
原文地址:https://www.cnblogs.com/Itst/p/9867615.html
时间: 2024-10-08 14:46:48