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
HINT
【样例说明】
下面是对样例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≤pici≤105。
题解
枚举哪些不送
第一个人送哪些
第二个人送哪些…
显然可以用一个组合数表达出来
发现p非质数
于是你需要扩展lucas了
具体 就刚学的吧我的blog!
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(!x){putchar('0');return ;}
static int sta[20],top=0;
while(x)sta[++top]=x%10,x/=10;
while(top)putchar(sta[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
LL pow_mod(LL a,LL b,LL mod)
{
LL ret=1;
while(b)
{
if(b&1)ret=ret*a%mod;
a=a*a%mod;b>>=1;
}
return ret;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(a==0)
{
x=0;y=1;
return b;
}
else
{
LL tx,ty;
LL d=exgcd(b%a,a,tx,ty);
x=ty-(b/a)*tx;
y=tx;
return d;
}
}
LL inv(LL A,LL mod)
{
LL x,y,K=1;
LL d=exgcd(A,mod,x,y);
x=(x*(K/d)%(mod/d)+(mod/d))%(mod/d);
return x;
}
LL solve(LL n,LL pi,LL mod)//非互质 mod=pi^k
{
if(!n)return 1;
LL ret=1;
for(int i=2;i<=mod;i++)if(i%pi)ret=ret*i%mod;
ret=pow_mod(ret,n/mod,mod);
for(int i=2;i<=n%mod;i++)if(i%pi)ret=ret*i%mod;
return ret*solve(n/pi,pi,mod)%mod;//递归计算另外一个阶乘pi^u*(1*2*3...)
}
LL exlucas(LL n,LL m,LL pi,LL mod)
{
if(m>n)return 0;
LL a=solve(n,pi,mod),b=solve(m,pi,mod),c=solve(n-m,pi,mod);
LL k=0;
for(LL i=n;i;i/=pi)k+=i/pi;
for(LL i=m;i;i/=pi)k-=i/pi;
for(LL i=n-m;i;i/=pi)k-=i/pi;
return a*inv(b,mod)%mod*inv(c,mod)%mod*pow_mod(pi,k,mod)%mod;
}
LL a1[100005],p1[100005],p2[100005],ln,P,n,m,temp;
LL query()
{
if(ln==1)return a1[1];
LL m1=p1[1],b1=a1[1],m2,b2;
for(int i=2;i<=ln;i++)
{
m2=p1[i];b2=a1[i];
LL A=m1,B=m2,K=b2-b1,x,y;
LL d=exgcd(A,B,x,y);
x=(x*(K/d)%(B/d)+(B/d))%(B/d);
b1=m1*x+b1;m1=m1/d*m2;
}
return b1;
}
LL work(LL n,LL m)
{
for(int i=1;i<=ln;i++)a1[i]=exlucas(n,m,p2[i],p1[i]);
return query()%temp;
}
int sum,w[10];
int main()
{
P=read();temp=P;
n=read();m=read();
for(int i=1;i<=m;i++)w[i]=read(),sum+=w[i];
if(sum>n)return puts("Impossible\n"),0;
for(int i=2;i*i<=P;i++)if(!(P%i))
{
ln++;p2[ln]=i;p1[ln]=1;
while(!(P%i))p1[ln]*=i,P/=i;
}
if(P!=1)ln++,p1[ln]=p2[ln]=P;
LL ans=work(n,n-sum);
for(int i=1;i<=m;i++)
{
ans=ans*work(sum,w[i])%temp;
sum-=w[i];
}
pr2(ans);
return 0;
}