P2640【SDOI2013 R1 Day2】方程
問題描述
輸入格式
輸入含有多組數據 ,第一行兩個 正整數 T,p。T表示這個測試點內的 數據 組數 ,p的含義見題目描述 。
對於每組數據,第一行 四個非負 整數 n,n1 ,n2 ,m。
第二行 n1+ n2 個正整數,表示 整數,表示 A1…An1+n2 。請注意,如果 。請注意,如果 n1+ n2 等於 0,那麼這一行將成爲空行
輸出格式
共 T行,每一個正整數表示取模後的答案
樣例輸入
3 10007
3 1 1 6
3 3
3 0 0 5
3 1 1 3
3 3
樣例輸出
3
6
0
提示
考慮沒有限制的情況,那麼顯然用隔板法求解,
考慮大於等於的限制,那麼顯然直接 即可。
考慮小於等於的限制,不好做,但限制數很少,考慮容斥。
那麼
顯然,後面的東西也是一個隔板法,那麼剩下的問題就是算組合數。
如果p是質數,直接Lucas,而本題p可能是合數,需要用到擴展Lucas,大體思路是利用CRT解方程,
即將p分解質因數,分別對每個 計算答案得到一組同餘方程,然後因爲模數互質,可以用CRT合併得到最終答案,具體請百度擴展Lucas
代碼:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#define N 15
#define ll long long
using namespace std;
struct node{ll a,b;};
bool operator<(node a,node b)
{
if(a.b==b.b)return a.a<b.a;
return a.b<b.b;
}
map<node,ll>Q;
ll T,p,A[N];
ll QM(ll a,ll b,ll c)
{
ll o=1;
while(b)
{
if(b&1)o=o*a%c;
b>>=1;a=a*a%c;
}
return o;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll inv(ll a,ll b)
{
ll x,y;exgcd(a,b,x,y);
x=(x%b+b)%b;
return x?x:x+b;
}
ll fac(ll n,ll px,ll pi)
{
if(!n)return 1;
node tmp=(node){n,px};
if(Q[tmp])return Q[tmp];
ll i,ans=1;
if(n/px)
{
for(i=2;i<=px;i++)if(i%pi)ans=ans*i%px;
ans=QM(ans,n/px,px);
}
for(i=2;i<=n%px;i++)if(i%pi)ans=ans*i%px;
return Q[tmp]=ans*fac(n/pi,px,pi)%px;
}
ll C(ll n,ll m,ll px,ll pi)
{
if(m>n)return 0ll;
ll a=fac(n,px,pi),b=fac(m,px,pi),c=fac(n-m,px,pi);
ll i,k=0,ans=0;
for(i=n;i;i/=pi)k+=i/pi;
for(i=m;i;i/=pi)k-=i/pi;
for(i=n-m;i;i/=pi)k-=i/pi;
ans=a*inv(b,px)%px*inv(c,px)%px*QM(pi,k,px)%px;
return ans*(p/px)%p*inv(p/px,px)%p;
}
ll Cal(ll n,ll m)
{
ll i,ans=0,x=p,px;
for(i=2;i<=x;i++)
{
if(x%i)continue;px=1;
while(x%i==0)px*=i,x/=i;
ans=(ans+C(n,m,px,i))%p;
}
return ans;
}
int main()
{
ll n,n1,n2,m,i,j,k,x,y,ans,S;
scanf("%lld%lld",&T,&p);
while(T--)
{
scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m);
for(i=1;i<=n1;i++)scanf("%lld",&A[i]);
for(i=1;i<=n2;i++)scanf("%lld",&x),m-=x-1;
ans=Cal(m-1,n-1);S=(1<<n1)-1;
for(i=1;i<=S;i++)
{
x=0;y=m;
for(j=1;j<=n1;j++)if(i>>j-1&1)x++,y-=A[j];
if(x&1)ans-=Cal(y-1,n-1),ans%=p;
else ans+=Cal(y-1,n-1),ans%=p;
}
printf("%lld\n",(ans%p+p)%p);
}
}