BZOJ 3129 [SDOI2013]方程 (拓展Lucas)
题目大意:给定一个方程$X_{1}+X_{2}+X_{3}+X_{4}+...+X_{n}=M$,$\forall X_{i}<=A_{i} (i<=n1)$ $\forall X_{i}>=A_{i} (n1<i<=n2)$在保证的合法正整数解个数n1<=8,n2<=8
一波三折的数学题,调了半天才发现我的Lucas是错的,但它竟然通过了洛谷那一道模板题的全部数据....
后面n1~n2的部分很好处理,直接用M减掉这个部分就行了
因为是求正整数解,所以这个组合数的形式可以用隔板法处理,即每两个物品之间设为一个空位,现在要分成n个部分,则把n-1个隔板放进空位
即$C_{m-1}^{k-1}$
前面1~n1的部分依然使用容斥的方法处理,类似于CF451E,状压+容斥
接下来就是拓展Lucas了,讲解传送门
1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N 10 7 #define ll long long 8 using namespace std; 9 10 ll exgcd(ll a,ll b,ll &x,ll &y){ 11 if(!b) {x=1,y=0;return a;} 12 ll g=exgcd(b,a%b,x,y); 13 ll t=x;x=y,y=t-a/b*y; 14 return g; 15 } 16 ll qmul(ll x,ll y,const ll &mo){ 17 ll ans=0; 18 while(y){ 19 if(y&1) ans=(ans+x)%mo; 20 x=(x+x)%mo,y>>=1; 21 }return ans; 22 } 23 ll qpow(ll x,ll y,const ll &mo){ 24 ll ans=1; 25 while(y){ 26 if(y&1) ans=ans*x%mo; 27 x=x*x%mo,y>>=1; 28 }return ans; 29 } 30 ll son1[]={10007}; 31 ll son2[]={2,3,11,397,10007}; 32 ll son3[]={5,7,101}; 33 34 namespace exlucas{ 35 ll ans=0,M=1; 36 ll son[10],pw[10]; 37 int num; 38 void Pre(ll p) 39 { 40 if(p==10007){ 41 num=1,son[0]=son1[0],pw[0]=son1[0]; 42 }else if(p==262203414){ 43 num=5; 44 for(int i=0;i<num;i++) 45 son[i]=son2[i],pw[i]=son[i]; 46 }else{ 47 num=3; 48 for(int i=0;i<num;i++) 49 son[i]=son3[i]; 50 pw[0]=125,pw[1]=343,pw[2]=10201; 51 } 52 } 53 int excrt_ins(ll A,ll B) 54 { 55 ll a=A,b=B,c=(a-ans%b+b)%b,x,y; 56 ll g=exgcd(M,b,x,y);ll bg=b/g; 57 if(c%g!=0) return -1; 58 //x=x*(c/g)%bg; 59 x=qmul(x,c/g,bg); 60 ans+=x*M,M*=bg,ans=(ans%M+M)%M; 61 return 1; 62 } 63 ll get_mul(ll n,ll p,ll &sum,const ll &mo,int type) 64 { 65 if(n==0) return 1; 66 ll ans=1; 67 for(int i=2;i<=min(n,mo);i++) 68 if(i%p) ans=ans*i%mo; 69 ans=qpow(ans,n/mo,mo); 70 for(int i=2;i<=n%mo;i++) 71 if(i%p) ans=ans*i%mo; 72 sum+=1ll*(n/p)*type; 73 return ans*get_mul(n/p,p,sum,mo,type)%mo; 74 } 75 ll get_C(ll n,ll m,ll p,const ll &mo) 76 { 77 if(m>n) return 0; 78 ll sum=0;ll y; 79 ll nn=get_mul(n,p,sum,mo,1); 80 ll mm=get_mul(m,p,sum,mo,-1); 81 ll nm=get_mul(n-m,p,sum,mo,-1); 82 exgcd(mm,mo,mm,y); 83 mm=(mm%mo+mo)%mo; 84 exgcd(nm,mo,nm,y); 85 nm=(nm%mo+mo)%mo; 86 return nn*mm%mo*nm%mo*qpow(p,sum,mo)%mo; 87 } 88 ll C(ll n,ll m,const ll &mo) 89 { 90 if(m>n) return 0; 91 ll ret=0; 92 for(int i=0;i<num;i++){ 93 ll val=get_C(n,m,son[i],pw[i]); 94 excrt_ins(val,pw[i]); 95 } 96 ret=ans,M=1,ans=0; 97 return ret; 98 } 99 }; 100 101 int T;ll p; 102 ll n,m,n1,n2; 103 ll a[N],b[N]; 104 105 int main() 106 { 107 // freopen("t1.in","r",stdin); 108 scanf("%d%lld",&T,&p); 109 exlucas::Pre(p); 110 while(T--) 111 { 112 scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m); 113 memset(a,0,sizeof(a));memset(b,0,sizeof(b)); 114 for(int i=0;i<n1;i++) scanf("%lld",&a[i]); 115 for(int i=1;i<=n2;i++) scanf("%lld",&b[i]),m-=(b[i]-1); 116 if(m<0) printf("0\n"); 117 int tot=(1<<n1);ll ans=0; 118 for(int s=0;s<tot;s++) 119 { 120 ll res=m;int cnt=0; 121 for(int i=0;i<n1;i++) if(s&(1<<i)) res-=a[i],cnt++; 122 if(res<=0) {continue;} 123 ll w=(cnt&1?-1ll:1ll)*exlucas::C(res-1,n-1,p); 124 (ans+=w)%=p; 125 } 126 printf("%lld\n",(ans%p+p)%p); 127 } 128 return 0; 129 }