BZOJ3129/洛谷P3301方程(SDOI2013)容斥原理+扩展Lucas定理
题意:给定方程x1+x2+....xn=m,每个x是正整数。但是对前n1个数做了限制x1<=a1,x2<=a2...xn1<=an1,同时对第n1+1到n1+n2个数也做了限制xn1+1>=an1+1....xn1+n2>=an1+n2,输出方程解个数。
解法:首先如果对数字没有任何要求(应该是只要求是非负数)的话,答案就是C(n+m+1,m+1)原理是隔板法。但是此题有各种限制,我们想办法解决限制使得答案往无限制上面靠。
首先是解决要正整数,那么每个数字减一即可,就是m-=n。
然后对于n1+1到n1+n2的限制,大于等于的限制也简单,也是xi>=ai的话就使xi-=ai即可。
好了到最麻烦的xi<=ai限制,这个限制我们没办法通过数字处理来解决。但是我们观察到这些限制个数小于等于8个,自然会想到容斥原理。
那么容斥原理常规套路,无限制-至少一个突破限制(也就是xi>ai为突破限制)方案数+至少两个数字突破限制.........
ok,解题思路就是上面这些。但是这题比较麻烦的在于:要计算的组合数非常大且模数不为质数!!!那么Lucas定理也不管用了,我们只能用到exLucas定理。
推荐看这篇博客:https://www.cnblogs.com/candy99/p/6637629.html
直接套上大佬的exLucas会TLE,有一些地方需要优化,①Lucas函数内每次都要找MOD的因子太慢了,先预处理出来。②Fac函数内每次暴力计算阶乘太慢了,需要在调用Fac之前即C函数处先预处理阶乘。
此题代码(注释的是修改大佬模板地方,加上优化):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
ll n,m,n1,n2,MOD,a[N];
ll tot=,f[N],c[N]; ll fac[N];
void Initfac(ll p,ll pr) { //预处理阶乘
fac[]=;
for(ll i=;i<=pr;i++)
if(i%p) fac[i]=fac[i-]*i%pr;
else fac[i]=fac[i-];
} ll Pow(ll a,ll b,ll P){
ll ans=;
for(;b;b>>=,a=a*a%P)
if(b&) ans=ans*a%P;
return ans;
}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y){
if(b==) d=a,x=,y=;
else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
ll Inv(ll a,ll n){
ll d,x,y;
exgcd(a,n,d,x,y);
return d==?(x+n)%n:-;
}
ll Fac(ll n,ll p,ll pr){
if(n==) return ;
ll re=;
//for(ll i=2;i<=pr;i++) if(i%p) re=re*i%pr;
re=fac[pr];
re=Pow(re,n/pr,pr);
ll r=n%pr;
//for(int i=2;i<=r;i++) if(i%p) re=re*i%pr;
re=re*fac[r]%pr;
return re*Fac(n/p,p,pr)%pr;
}
ll C(ll n,ll m,ll p,ll pr){
if(n<m) return ;
Initfac(p,pr); //预处理阶乘
ll x=Fac(n,p,pr),y=Fac(m,p,pr),z=Fac(n-m,p,pr);
ll c=;
for(ll i=n;i;i/=p) c+=i/p;
for(ll i=m;i;i/=p) c-=i/p;
for(ll i=n-m;i;i/=p) c-=i/p;
ll a=x*Inv(y,pr)%pr*Inv(z,pr)%pr*Pow(p,c,pr)%pr;
return a*(MOD/pr)%MOD*Inv(MOD/pr,pr)%MOD;
}
ll Lucas(ll n,ll m){ //exLucas
ll x=MOD,re=;
// for(ll i=2;i<=MOD;i++) if(x%i==0){
// ll pr=1;
// while(x%i==0) x/=i,pr*=i;
// re=(re+C(n,m,i,pr))%MOD;
// }
for (int i=;i<=tot;i++) re=(re+C(n,m,f[i],c[i]))%MOD;
return re;
} void prework(ll n) {
ll t=n;
for (int i=;(ll)i*i<=n;i++) {
if (t%i==) {
tot++; f[tot]=i; c[tot]=;
while (t%i==) t/=i,c[tot]*=i;
}
}
if (t>) f[++tot]=t,c[tot]=t;
} int main()
{
int T; scanf("%d%lld",&T,&MOD);
prework(MOD);
while(T--) {
scanf("%lld%d%d%lld",&n,&n1,&n2,&m);
for(int i=;i<=n1+n2;i++) scanf("%lld",&a[i]);
for(int i=;i<=n2;i++) m-=a[n1+i]-;
m-=n; ll ans=;
for(int i=;i<(<<n1);i++) {
int tot=;
ll x=m;
for(int j=;j<n1;j++)
if (i&(<<j)) { tot++; x-=a[j+]; }
if (tot%) ans=(ans-Lucas(x+n-,n-)+MOD)%MOD;
else ans=(ans+Lucas(x+n-,n-))%MOD;
}
printf("%lld\n",ans);
}
return ;
}
记录下大佬的exLucas定理模板:
ll Pow(ll a,ll b,ll P){
ll ans=;
for(;b;b>>=,a=a*a%P)
if(b&) ans=ans*a%P;
return ans;
}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y){
if(b==) d=a,x=,y=;
else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
ll Inv(ll a,ll n){
ll d,x,y;
exgcd(a,n,d,x,y);
return d==?(x+n)%n:-;
}
ll Fac(ll n,ll p,ll pr){
if(n==) return ;
ll re=;
for(ll i=;i<=pr;i++) if(i%p) re=re*i%pr;
re=Pow(re,n/pr,pr);
ll r=n%pr;
for(int i=;i<=r;i++) if(i%p) re=re*i%pr;
return re*Fac(n/p,p,pr)%pr;
}
ll C(ll n,ll m,ll p,ll pr){
if(n<m) return ;
ll x=Fac(n,p,pr),y=Fac(m,p,pr),z=Fac(n-m,p,pr);
ll c=;
for(ll i=n;i;i/=p) c+=i/p;
for(ll i=m;i;i/=p) c-=i/p;
for(ll i=n-m;i;i/=p) c-=i/p;
ll a=x*Inv(y,pr)%pr*Inv(z,pr)%pr*Pow(p,c,pr)%pr;
return a*(MOD/pr)%MOD*Inv(MOD/pr,pr)%MOD;
}
ll Lucas(ll n,ll m){
ll x=MOD,re=;
for(ll i=;i<=MOD;i++) if(x%i==){
ll pr=;
while(x%i==) x/=i,pr*=i;
re=(re+C(n,m,i,pr))%MOD;
}
return re;
}
BZOJ3129/洛谷P3301方程(SDOI2013)容斥原理+扩展Lucas定理的更多相关文章
- BZOJ3129 SDOI2013方程(容斥原理+扩展lucas)
没有限制的话算一个组合数就好了.对于不小于某个数的限制可以直接减掉,而不大于某个数的限制很容易想到容斥,枚举哪些超过限制即可. 一般情况下n.m.p都是1e9级别的组合数没办法算.不过可以发现模数已经 ...
- 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)
题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...
- 【learning】 扩展lucas定理
首先说下啥是lucas定理: $\binom n m \equiv \binom {n\%P} {m\%P} \times \binom{n/P}{m/P} \pmod P$ 借助这个定理,求$\bi ...
- 2015 ICL, Finals, Div. 1 Ceizenpok’s formula(组合数取模,扩展lucas定理)
J. Ceizenpok’s formula time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- BZOJ - 2142 礼物 (扩展Lucas定理)
扩展Lucas定理模板题(貌似这玩意也只能出模板题了吧~~本菜鸡见识鄙薄,有待指正) 原理: https://blog.csdn.net/hqddm1253679098/article/details ...
- [bzoj2142]礼物(扩展lucas定理+中国剩余定理)
题意:n件礼物,送给m个人,每人的礼物数确定,求方案数. 解题关键:由于模数不是质数,所以由唯一分解定理, $\bmod = p_1^{{k_1}}p_2^{{k_2}}......p_s^{{k_ ...
- Lucas定理和扩展Lucas定理
1.Lucas定理 首先给出式子:\(C_n^m\%p = C_{\lfloor\frac{n}{p}\rfloor}^{\lfloor\frac{m}{p}\rfloor} * C_{n\%p}^{ ...
- Ceizenpok’s formula Gym - 100633J 扩展Lucas定理 + 中国剩余定理
http://codeforces.com/gym/100633/problem/J 其实这个解法不难学的,不需要太多的数学.但是证明的话,我可能给不了严格的证明.可以看看这篇文章 http://ww ...
- [笔记] 扩展Lucas定理
[笔记] 扩展\(Lucas\)定理 \(Lucas\)定理:\(\binom{n}{m} \equiv \binom{n/P}{m/P} \binom{n \% P}{m \% P}\pmod{P} ...
随机推荐
- Andorid 手机WIFI连接的Mac地址和IP地址
public static String getInfo() { WifiManager wifi = (WifiManager) getSystemService(Contex ...
- 走进JavaWeb技术世界14:Mybatis入门
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- zk的KeeperErrorCode = ConnectionLoss错误
额,这东西都快把人搞崩溃了,各种排查各种正常. 最后竟然是因为我在客户端未连接上zkserver的时候就进行了create操作造成的错误. 噗, Exception in thread "m ...
- 浅释Functor、Applicative与Monad
引言 转入Scala一段时间以来,理解Functor.Applicative和Monad等概念,一直是我感到头疼的部分.虽然读过<Functors, Applicatives, And Mona ...
- CGI FastCGI WSGI 解析
我们将服务端程序分为了web服务器和应用程序服务器. web服务器是用于处理HTML文件,让客户可以通过浏览器进行访问.主流的有apache,IIS,nginx,lghttpd等. 应用服务器处理业务 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_3_对象的反序列化流_ObjectInputStream
声明了IO异常,这里还是红色的 转换为Person对象
- iptables中文帮助
Iptables(8) ...
- SQL server 2008r2 file is corrupt
下载的SQLManagement studio有问题,重新下载一遍后再安装就好了.安装顺序没问题. 在卸载SQL Server开始——运行:输入regedit 进入注册表编辑器,进入之后执行下列操作: ...
- pycharm中的Terminal 中无法使用git的问题
1.先找到git的安装路径,建议使用Everything工具 2.打开pycharm中的setting > tools > Terminal 3.把git的安装路径加上启动文件 bash. ...
- levelDB SSTable-静态布局结构
SSTable是Bigtable中至关重要的一块,对于LevelDB来说也是如此,对LevelDB的SSTable实现细节的了解也有助于了解Bigtable中一些实现细节. 本节内容主要讲述S ...