BZOJ 3129 SDOI2013 方程
2016-04-14 21:33
357 查看
如果没有限制,答案直接用隔板法C(m-1,n-1)
对于>=x的限制,我们直接在对应位置先放上x-1即可,即m=m-(x-1)
对于<=x的限制,由于限制很小我们可以利用容斥原理将它转化为上面的>=x的限制
即减去1个不满足的 加上2个不满足的 减去3个不满足的 ……
之后就是组合数的计算,对于一个非常大的模数,我们可以将它唯一分解,之后CRT还原即可
但是我们有可能不存在逆元,数据范围不允许我们递推计算组合数
我们知道没有逆元当且仅当(a,p)不互素,我们可以将阶乘分成两部分:互素和不互素
互素的部分具有循环节,我们暴力计算循环节之后快速幂即可
不互素的部分我们可以提出他们的gcd出来并记录指数,剩余部分又变成了计算阶乘,递归即可
对于>=x的限制,我们直接在对应位置先放上x-1即可,即m=m-(x-1)
对于<=x的限制,由于限制很小我们可以利用容斥原理将它转化为上面的>=x的限制
即减去1个不满足的 加上2个不满足的 减去3个不满足的 ……
之后就是组合数的计算,对于一个非常大的模数,我们可以将它唯一分解,之后CRT还原即可
但是我们有可能不存在逆元,数据范围不允许我们递推计算组合数
我们知道没有逆元当且仅当(a,p)不互素,我们可以将阶乘分成两部分:互素和不互素
互素的部分具有循环节,我们暴力计算循环节之后快速幂即可
不互素的部分我们可以提出他们的gcd出来并记录指数,剩余部分又变成了计算阶乘,递归即可
#include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<algorithm> using namespace std; const int maxn=110; typedef long long LL; int T,tot=0; LL p,n,n1,n2,m; LL mod[maxn],prime[maxn],a[maxn]; LL Num[maxn]; LL x,y,d; LL ans; void Get_mod(LL x){ for(int i=2;i*i<=x;++i){ if(x%i==0){ prime[++tot]=i;mod[tot]=1; while(x%i==0){x/=i;mod[tot]*=i;} } } if(x>1)prime[++tot]=x,mod[tot]=x; } void ex_gcd(LL a,LL b,LL &x,LL &y,LL &d){ if(b==0){x=1;y=0;d=a;} else{ex_gcd(b,a%b,y,x,d);y-=(a/b)*x;} } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=tmp*v%mod; v=v*v%mod;p>>=1; }return tmp; } LL inv(LL a,LL b){ ex_gcd(a,b,x,y,d); return (x%b+b)%b; } LL CRT(){ LL ans=0; for(int i=1;i<=tot;++i){ LL m=p/mod[i]; ex_gcd(mod[i],m,d,y,d); ans=(ans+y*m*a[i])%p; }return (ans+p)%p; } pair<LL,LL> fac(int k,LL n){ if(n==0)return make_pair(0,1); int x=n/prime[k],y=n/mod[k]; LL ans=1; if(y){ for(int i=2;i<mod[k];++i)if(i%prime[k]!=0)ans=(ans*1LL*i)%mod[k]; ans=pow_mod(ans,y,mod[k]); } for(int i=y*mod[k]+1;i<=n;++i)if(i%prime[k]!=0)ans=(ans*1LL*i)%mod[k]; pair<LL,LL> tmp=fac(k,x); return make_pair(x+tmp.first,ans*tmp.second%mod[k]); } LL cal(int k,LL n,LL m){ if(n<m)return 0; pair<LL,LL> a=fac(k,n),b=fac(k,m),c=fac(k,n-m); return pow_mod(prime[k],a.first-b.first-c.first,mod[k])*a.second%mod[k] *inv(b.second,mod[k])%mod[k]*inv(c.second,mod[k])%mod[k]; } LL C(LL n,LL m){ for(int i=1;i<=tot;++i)a[i]=cal(i,n,m); return CRT(); } void DFS(int pos,int now,LL sum){ if(pos>n1){ if(now)ans-=C(m-1-sum,n-1); else ans+=C(m-1-sum,n-1); ans=(ans+p)%p; return; } DFS(pos+1,now,sum); DFS(pos+1,now^1,sum+Num[pos]); } int main(){ scanf("%d%lld",&T,&p); Get_mod(p); while(T--){ scanf("%lld%lld%lld%lld",&n,&n1,&n2,&m); for(int i=1;i<=n1;++i)scanf("%lld",&Num[i]); for(int i=1;i<=n2;++i){scanf("%lld",&x);m=m-x+1;} ans=0; DFS(1,0,0); printf("%lld\n",(ans+p)%p); }return 0; }
相关文章推荐
- hadoop 安装与配置
- 最长递增子序列
- CSS学习笔记总结和技巧
- C语言中以十六进制输出字符型变量会出现'ffffff"的问题
- 20145305 《Java程序设计》第7周学习总结
- 写在心有余力有余的大二下学期
- MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk
- 浏览器对HTML5特性检测工具Modernizr
- 关于mybatis Invalid bound statement (not found) 问题
- POJ 3069 Saruman's Army 贪心算法
- Teacher_Cadre c++多文件编程
- OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co
- 单例模式与双重检测
- ACM刷题之HDU————N!Again
- FusionCharts简单教程(四)-----基本数字格式
- 1.2.1 Minix
- C语言中的sizeof和strlen
- Java中的5种同步辅助类
- java 背后的小动作
- 贝叶斯定理