题目链接

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^3三种。

题解

假设没有限制,那么答案就是(m1n1)\binom{m-1}{n-1}。这个可以很容易用扩展lucas求出。

第二种限制相当于将xix_imm同时(Ai1)-(A_i-1)

对于第一种限制,考虑至少不满足BB集合中限制的情况,相当于将xix_imm同时(Ai1)-(A_i-1),其中iBi\in 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;
}