bzoj3129[Sdoi2013]方程 exlucas+容斥原理
3129: [Sdoi2013]方程
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 582 Solved: 338
[Submit][Status][Discuss]
Description
给定方程
X1+X2+. +Xn=M
我们对第l..N1个变量进行一些限制:
Xl < = A
X2 < = A2
Xn1 < = An1
我们对第n1 + 1..n1+n2个变量进行一些限制:
Xn1+l > = An1+1
Xn1+2 > = An1+2
Xnl+n2 > = Anl+n2
求:在满足这些限制的前提下,该方程正整数解的个数。
答案可能很大,请输出对p取模后的答案,也即答案除以p的余数。
Input
输入含有多组数据,第一行两个正整数T,p。T表示这个测试点内的数据组数,p的含义见题目描述。
对于每组数据,第一行四个非负整数n,n1,n2,m。
第二行nl+n2个正整数,表示A1..n1+n2。请注意,如果n1+n2等于0,那么这一行会成为一个空行。
Output
共T行,每行一个正整数表示取模后的答案。
Sample Input
3 10007
3 1 1 6
3 3
3 0 0 5
3 1 1 3
3 3
Sample Output
3
6
0
【样例说明】
对于第一组数据,三组解为(1,3,2),(1,4,1),(2,3,1)
对于第二组数据,六组解为(1,1,3),(1,2,2),(1,3,1),(2,1,2),(2,2,1),(3,1,1)
HINT
n < = 10^9 , n1 < = 8 , n2 < = 8 , m < = 10^9 ,p<=437367875
对于l00%的测试数据: T < = 5,1 < = A1..n1_n2 < = m,n1+n2 < = n
exlucas+容斥啊。
这道题主要考点是exlucas而不是容斥吧。
模型转换可以看成向盒子里装小球 ,转化成隔板原理
而由于组合数C(n,m)中n和m太大了且p不一定是质数,需要用exlucas来求组合数模
对于有下界限制的,强行先分给它 下界-1个
对于上界限制的直接容斥 没超的-至少1个超的+至少2个超的..
exlucas可以翻翻网上博客,主要就用了CRT和快速求阶乘来得到组合数
代码我懒得写了,复制了别人的
lucas&&exlucas https://www.cnblogs.com/candy99/p/6637629.html
这道题代码原网址:http://blog.csdn.net/werkeytom_ftd/article/details/50152143
#include<cstdio> #include<iostream> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; typedef long long ll; ll f[10],a[20],b[20],c[20],d[20],e[20],pri[32000+10],fac[100000+10]; bool bz[32000+10]; ll i,j,k,l,t,n,m,n1,n2,ca,p,pp,num,top,xx,yy,cnt; ll quicksortmi(ll x,ll y,ll p){ if (!y) return 1; if (y==1) return x%p; ll t=quicksortmi(x,y/2,p); t=t*t%p; if (y%2) t=t*(x%p)%p; return t; } void gcd(ll a,ll b){ if (!b){ xx=1; yy=0; } else{ gcd(b,a%b); swap(xx,yy); yy-=xx*(a/b); } } ll getny(ll x,ll y){ gcd(x,y); xx=(xx%y+y)%y; return xx; } ll calcfac(ll n,ll p,ll pp){ if (n<pp) return fac[n]; ll t=quicksortmi(fac[p-1],n/p,p); t=t*fac[n%p]%p; cnt+=n/pp; t=t*calcfac(n/pp,p,pp)%p; return t; } ll calc(ll x,ll y,ll p,ll pp){ ll i; fac[0]=1; fo(i,1,p-1) if (i%pp==0) fac[i]=fac[i-1]; else fac[i]=fac[i-1]*i%p; cnt=0; ll A=calcfac(y,p,pp); ll tot=cnt; cnt=0; ll B=calcfac(x,p,pp); B=B*calcfac(y-x,p,pp)%p; B=getny(B,p); return A*B%p*quicksortmi(pp,tot-cnt,p)%p; } ll comb(ll x,ll y,ll p){ if (x>y) return 0; fo(i,1,top) a[i]=calc(x,y,d[i],e[i]); fo(i,1,top) b[i]=getny(c[i],d[i]); ll t=0; fo(i,1,top) t=(t+a[i]*b[i]%p*c[i]%p)%p; return t; } void dfs(ll x,ll m,ll cnt){ if (x==n1+1){ ll t=comb(n-1,m-1,p); if (cnt%2) num=((num-t)%p+p)%p; else num=(num+t)%p; return; } dfs(x+1,m,cnt); if (m-f[x]) dfs(x+1,m-f[x],cnt+1); } int main(){ fo(i,2,32000){ if (!bz[i]) pri[++k]=i; fo(j,1,k){ if (pri[j]*i>32000) break; bz[i*pri[j]]=1; if (i%pri[j]==0) break; } } scanf("%lld%lld",&ca,&p); pp=p; fo(i,1,k){ if (pp%pri[i]==0){ d[++top]=1;e[top]=pri[i]; while (pp%pri[i]==0){ d[top]*=pri[i]; pp/=pri[i]; } } } fo(i,1,top) c[i]=p/d[i]; while (ca--){ scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m); fo(i,1,n1) scanf("%lld",&f[i]); fo(i,1,n2){ scanf("%lld",&k); if (k) m-=k-1; } num=0; dfs(1,m,0); printf("%lld\n",num); } }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。