题解 P2183 【[国家集训队]礼物】
没人在这里发这题题解啊,我来发一篇。
明显答案是Impossible。
求解一个组合数
具体地,对于求
考虑求解答案,因为模的是一个和数,所以不能直接用普通的
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=6;
const int maxp=(int)1e5+5;
int P,n,m,w[maxn],pri[maxp],cnt[maxp],tot=0,c[maxp],R[maxp],M[maxp];
map<int ,int > re;
inline int maybs(int x) {return x<0?-x:x;}
void div(int x)
{
for(int i=2;i*i<=x;i++) {
if(x%i==0) {
pri[++tot]=i;re[i]=tot;
while(x%i==0) x/=i,cnt[tot]++;
}
}
if(x!=1) {
if(re.find(x)==re.end()) pri[++tot]=x,re[x]=tot;
cnt[re[x]]++;
}
}
int quickpow(int x,int k)
{
int ret=1;
while(k>0) {
if(k&1) ret=ret*x;
x=x*x; k>>=1;
}
return ret;
}
int quickpow(int x,int k,int mo)
{
int ret=1;
while(k>0) {
if(k&1) ret=1ll*ret*x%mo;
x=1ll*x*x%mo; k>>=1;
}
return ret;
}
int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}
int extgcd(int a,int b,int &x,int &y)
{
if(b==0) {x=1,y=0; return a;}
else {int d=extgcd(b,a%b,y,x);y-=a/b*x;return d;}
}
int inv(int q,int p)
{
assert(gcd(p,q)==1);
int x,y;
extgcd(q,p,x,y);
x=(x%p+p)%p; if(!x) x+=p;
return x;
}
int Cnt(int x,int p) {
if(x==0) return 0;
return Cnt(x/p,p)+x/p;
}
typedef pair<int ,int > pii;
#define fir first
#define sec second
#define MP make_pair
pii Cal(int x,int p,int k)
{
if(x==1 || x==0) return MP(1,0);
int ret=1,del=0,tmp=quickpow(p,k);
int cou=Cnt(x,p);
del=cou;
pii nw=Cal(x/p,p,k);
ret=1ll*ret*nw.fir%tmp;
if(x>=tmp) {
int lev=1;
for(int i=1;i<tmp;i++) {
if(i%p==0) continue;
lev=1ll*lev*i%tmp;
}
ret=1ll*ret*quickpow(lev,x/tmp,tmp)%tmp;
}
for(int i=x;i>=1;i--) {
if(i%tmp==0) break;
if(i%p==0) continue;
ret=1ll*ret*i%tmp;
}
return MP(ret,del);
}
int getAns()
{
for(int i=1;i<=tot;i++) M[i]=1;
for(int i=1;i<=tot;i++) {
for(int j=1;j<=tot;j++)
if(i==j) continue;
else M[i]=1ll*M[i]*R[j]%P;
}
int ret=0;
for(int i=1;i<=tot;i++) ret=(ret+((1ll*c[i]*M[i]%P)*1ll*inv(M[i],R[i]))%P)%P;
return ret;
}
int main()
{
scanf("%d",&P);
div(P);
scanf("%d%d",&n,&m);
int sum=0;
for(int i=1;i<=m;i++) {scanf("%d",&w[i]);sum+=w[i];}
if(sum>n) {printf("Impossible\n");exit(0);}
int ans=1,N=n,M,res=1;
pii up,dw1,dw2;
for(int i=1;i<=m;i++) {
M=w[i];
for(int j=1;j<=tot;j++) R[j]=quickpow(pri[j],cnt[j]);
for(int j=1;j<=tot;j++) {
ans=1;
up=Cal(N,pri[j],cnt[j]);
dw1=Cal(M,pri[j],cnt[j]),dw2=Cal(N-M,pri[j],cnt[j]);
up.sec-=dw1.sec; up.sec-=dw2.sec;
assert(up.sec>=0);
if(up.sec>=cnt[j]) ans=0;
else {
ans=1ll*ans*up.fir%R[j];
ans=1ll*ans*inv(dw1.fir,R[j])%R[j]; ans=1ll*ans*inv(dw2.fir,R[j])%R[j];
ans=1ll*ans*quickpow(pri[j],up.sec,R[j])%R[j];
}
c[j]=ans;
}
res=1ll*res*getAns()%P;
N-=w[i];
}
printf("%d\n",res);
return 0;
}