【BZOJ 2142】 礼物

2019-04-13 21:33发布

2142: 礼物

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 701  Solved: 283
[Submit][Status][Discuss]

Description

一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人,其中送给第i个人礼物数量为wi。请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某个人在这两种方案中收到的礼物不同)。由于方案数可能会很大,你只需要输出模P后的结果。

Input

输入的第一行包含一个正整数P,表示模;第二行包含两个整整数n和m,分别表示小E从商店购买的礼物数和接受礼物的人数;以下m行每行仅包含一个正整数wi,表示小E要送给第i个人的礼物数量。

Output

若不存在可行方案,则输出“Impossible”,否则输出一个整数,表示模P后的方案数。

Sample Input

100 4 2 1 2

Sample Output

12


【样例说明】
下面是对样例1的说明。
以“/”分割,“/”前后分别表示送给第一个人和第二个人的礼物编号。12种方案详情如下:
1/23 1/24 1/34
2/13 2/14 2/34
3/12 3/14 3/24
4/12 4/13 4/23
【数据规模和约定】
设P=p1^c1 * p2^c2 * p3^c3 * … *pt ^ ct,pi为质数。
对于100%的数据,1≤n≤109,1≤m≤5,1≤pi^ci≤10^5。

组合数取模终极题目。
这道题的答案很好算C(n,tot)+C(tot,w[1])+C(tot-w[1],w[2])+...
由于n很大,想到用lucas定理,但是模不是质数!!
首先质数的幂之间一定互质,那么我们可以把模分解成几个质数的幂的乘积的形式,对每一个质数的幂求解,然后用中国剩余定理将他们合并起来即可。
那么如何快速计算组合数对质数的幂取模呢?
C(n,m)=n!/(m!*(n-m)!)
我们可以把分子分母分别化成t1*p^u1,t2*p^u2的形式,然后把C(n,m)=t1/t2 *p^(u1-u2),此时t1/t2可以用扩展欧几里得直接求出,乘上p^(u1-u2)就是答案。
可是如何快速求出n!=t*p^u的t和u的值呢?
我们把所有是p的倍数的数提出来,先不考虑。
先考虑t的值(注意所有是p的倍数的数不参与计算): 如果y=n/(p^u),如果y>1那么我们可以算出1-p^u的值为ans,那么t=ans^y*剩下数的乘积,否则直接暴力算1-n
再看u的值,p的倍数的数有1*p,2*p,3*p.....k*p(k=n/p),我们把p提出来之后就变成了1,2,3...k,于是问题变成了更小规模的原问题!递归解决即可~ 复杂度是线性的~
#include #include #include #include #include #include #define N 100000+5 #define LL long long #define pa pair #define mp make_pair #define fi first #define se second using namespace std; LL mod,a[N]; int n,m,v[N],p[N],s[100],tot,num; struct divi { int p,c,pc; }w[N]; void Prepare() { int cnt=0; for (int i=2;i<=100000;i++) if (!v[i]) { p[++cnt]=i; for (int j=i;j<=100000;j+=i) v[j]=1; } num=0; LL x=mod; for (int i=1;i<=cnt;i++) { if (x<=1) break; if (x%p[i]) continue; w[++num].p=p[i]; w[num].pc=1; while (x%p[i]==0) w[num].c++,x/=p[i],w[num].pc*=p[i]; } } LL Pow(LL a,int n,LL mod) { LL base=a,ans=1; while (n) { if (n&1) ans=ans*base%mod; base=base*base%mod; n>>=1; } return ans; } void Exgcd(LL a,LL b,LL &d,LL &x,LL &y) { if (!b) { d=a,x=1,y=0; return; } Exgcd(b,a%b,d,y,x); y-=x*(a/b); } LL Inv(LL a,LL n) { LL xx,yy,d; Exgcd(a,n,d,xx,yy); return (xx%n+n)%n; } pa Fac(int k,LL n) { if (n==0) return mp(0,1); int x=n/w[k].p,y=n/w[k].pc; LL ans=1; if (y) { for (int i=2;in) { puts("Impossible"); return 0; } ans=C(n,tot)%mod; for (int i=1;i<=m;i++) { ans=ans*C(tot,s[i])%mod; tot-=s[i]; } printf("%lld ",ans); return 0; }