题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=3129
题面有坑,模数只有10007,262203414=10007×397×11×3×2,437367875=1012×73×5310007,262203414=10007\times 397\times 11\times 3\times 2,437367875=101^2\times 7^3\times 5^310007,262203414=10007×397×11×3×2,437367875=1012×73×53三种。
题解
假设没有限制,那么答案就是(m−1n−1)\binom{m-1}{n-1}(n−1m−1)。这个可以很容易用扩展lucas求出。
第二种限制相当于将xix_ixi和mmm同时−(Ai−1)-(A_i-1)−(Ai−1)。
对于第一种限制,考虑至少不满足BBB集合中限制的情况,相当于将xix_ixi和mmm同时−(Ai−1)-(A_i-1)−(Ai−1),其中i∈Bi\in Bi∈B。容斥一下即可。
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
typedef std::pair<int,int> pii;
const int maxn=8;
const int maxt=10;
int t,mod,n,m,k,ans,lim[maxn+2],exmod[maxt+2],cnt[maxt+2],ext,tmod[maxt+2],cval[maxt+2];
int extract(int p)
{
for(int i=2; i*i<=p; ++i)
{
if(p%i==0)
{
exmod[++ext]=i;
tmod[ext]=1;
while(p%i==0)
{
++cnt[ext];
p/=i;
tmod[ext]*=i;
}
}
}
if(p!=1)
{
exmod[++ext]=p;
cnt[ext]=1;
tmod[ext]=p;
}
return 0;
}
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int g=exgcd(b,a%b,x,y),ti=x;
x=y;
y=ti-(a/b)*x;
return g;
}
int quickpow(int a,int b,int mo)
{
int res=1;
while(b)
{
if(b&1)
{
res=1ll*res*a%mo;
}
a=1ll*a*a%mo;
b>>=1;
}
return res;
}
int getrev(int a,int b)
{
int x,y;
int g=exgcd(a,b,x,y);
if(g!=1)
{
return -1;
}
x=x%b+b;
if(x<0)
{
x+=b;
}
if(x>=b)
{
x-=b;
}
return x;
}
int crt()
{
int res=0;
for(int i=1; i<=ext; ++i)
{
res=(res+1ll*cval[i]*(mod/tmod[i])%mod*getrev(mod/tmod[i],tmod[i]))%mod;
}
return res;
}
pii getfac(int x,int p)
{
if(x==0)
{
return std::make_pair(0,1);
}
int a=x/exmod[p],b=1;
for(int i=1; i<=tmod[p]; ++i)
{
if(i%exmod[p])
{
b=1ll*b*i%mod;
}
}
b=quickpow(b,x/tmod[p],tmod[p]);
for(int i=1; i<=x%tmod[p]; ++i)
{
if(i%exmod[p])
{
b=1ll*b*i%mod;
}
}
pii l=getfac(x/exmod[p],p);
return std::make_pair(a+l.first,(int)(1ll*b*l.second%mod));
}
int calc(int a,int b,int p)
{
pii x=getfac(a,p),y=getfac(b,p),z=getfac(a-b,p);
cval[p]=1ll*quickpow(exmod[p],x.first-y.first-z.first,tmod[p])*x.second%mod*getrev(y.second,tmod[p])%mod*getrev(z.second,tmod[p])%mod;
return 0;
}
int C(int a,int b)
{
if(a<b)
{
return 0;
}
for(int i=1; i<=ext; ++i)
{
calc(a,b,i);
}
return crt();
}
int search(int now,int li,int rm)
{
if(now>k)
{
int c=C(li-1,n-1);
if(rm&1)
{
ans-=c;
if(ans<0)
{
ans+=mod;
}
}
else
{
ans+=c;
if(ans>=mod)
{
ans-=mod;
}
}
return 0;
}
search(now+1,li,rm);
if(li-lim[now]>=n)
{
search(now+1,li-lim[now],rm+1);
}
return 0;
}
int main()
{
t=read();
mod=read();
extract(mod);
while(t--)
{
n=read();
k=read();
int a=read();
m=read();
for(int i=1; i<=k; ++i)
{
lim[i]=read();
}
for(int i=1; i<=a; ++i)
{
int b=read();
m-=b-1;
}
if(m<n)
{
puts("0");
continue;
}
ans=0;
search(1,m,0);
printf("%d\n",ans);
}
return 0;
}