题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3129

题解:

容斥,扩展Lucas,中国剩余定理

先看看不管限制,只需要每个位置都是正整数时的方案数的求法。
假设有 N 个未知数,加起来的和为 M。
转化一下问题变为:"小球分配"
有 M 个相同的小球,放在 N 个盒子里,且每个盒子至少有一个的方案数。
那么方案数为 ${C}_{M-1}^{N-1}$
怎么理解这个式子呢?"插隔板法"。
使 M个小球放在一排,考虑可以在相邻小球的空隙间(共 M-1个空隙)插入一个隔板,总共插入 N-1个隔板。
把相邻的两个隔板(把首尾也看作另外2个隔板)中间的区域看做一个个的盒子,区域内的小球即为该盒子里的小球。
则任意一种插隔板的方法都对应一种把小球放入盒子的方法。
所以方案数为
${C}_{M-1}^{N-1}$

对于题目给的两种限制,不要被吓到了。
其实大于等于(>=W)这一个限制很好处理,直接把 M-=(W-1),即事先给这些位置分配 W-1个小球。
因为接下来按照上面的 "小球分配" 方式,这些限制一定可以满足。
然后对于小于等于(<=W) 就需要用到容斥了。
定义 f[S] 表示至少 S 集合里面的这些"小于等于"限制都不能满足,那么方案数的求法就是:
先强制给这些盒子分配 Wi 个小球,
使得接下来按照上面的 "小球分配" 方式求出方案数,这些盒子一定会超过限制。
所以按照容斥的做法:
答案 ANS = 至少 0 个盒子超出限制的方案数
                - 至少 1 个盒子超出限制的方案数
                +至少 2 个盒子超出限制的方案数
                -...+...

但是求那个方案数 C(N,M) 就比较麻烦了,因为 N,M很大,且模数不保证为质数,
所以用到 扩展Lucas(+国剩) 来求。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define _ % P
#define filein(x) freopen(#x".in","r",stdin);
#define fileout(x) freopen(#x".out","w",stdout);
using namespace std;
int h[300],k[300],d[300],pi[10],ppi[10],fc[10][100500],pnt;
int T,N,N1,N2,M,ANS;
void init(){
ANS=0;
memset(h,0,sizeof(h));
memset(k,0,sizeof(k));
memset(d,0,sizeof(d));
}
void pre_prime(int P){
static bool np[100500];
static int prime[100500],cnt;
for(int i=2;i<=100000;i++){
if(!np[i]){
prime[++cnt]=i;
if(P%i==0){
pi[++pnt]=i; ppi[pnt]=1;
while(P%i==0) ppi[pnt]*=i,P/=i;
}
}
for(int j=1;j<=cnt&&i<=100000/prime[j];j++){
np[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
for(int i=1;i<=pnt;i++){
fc[i][0]=1;
for(int j=1;j<=100000;j++)
fc[i][j]=(1ll*fc[i][j-1]*(j%pi[i]?j:1))%ppi[i];
}
}
int pow(int a,int b,int P){
int ret=1; a=(a)_;
while(b){
if(b&1) ret=(1ll*ret*a)_;
a=(1ll*a*a)_; b>>=1;
}
return ret;
}
void exEuclidean(int a,int b,int &g,long long &x,long long &y){
if(!b) g=a,x=1,y=0;
else exEuclidean(b,a%b,g,y,x),y-=(a/b)*x;
}
int inv(int a,int P){
int g; long long x,y;
exEuclidean(a,P,g,x,y);
x=((1ll*x)_+P)_;
return (int)x;
}
int fac(int n,int I,int Pi,int P){
if(!n) return 1; int ret=1,r=n%P;
//for(int i=2;i<=P;i++) if(i%Pi) ret=(1ll*ret*i)_;
ret=fc[I][P];
ret=pow(ret,n/P,P);
//for(int i=2;i<=r;i++) if(i%Pi) ret=(1ll*ret*i)_;
ret=(1ll*ret*fc[I][r])_;
return (1ll*ret*fac(n/Pi,I,Pi,P))_;
}
int C(int n,int m,int I,int Pi,int P){
int x,y,z,c=0;
x=fac(n,I,Pi,P); y=fac(m,I,Pi,P); z=fac(n-m,I,Pi,P);
for(int i=n;i;i/=Pi) c+=i/Pi;
for(int i=m;i;i/=Pi) c-=i/Pi;
for(int i=n-m;i;i/=Pi) c-=i/Pi;
return ((((1ll*x*inv(y,P))_)*inv(z,P))_*pow(Pi,c,P))_;
}
int exLucas(int n,int m,int P){
int ret=0,tmp; if(n<m) return 0;
for(int i=1;i<=pnt;i++){
tmp=C(n,m,i,pi[i],ppi[i]);
tmp=((1ll*tmp*(P/ppi[i]))_*inv(P/ppi[i],ppi[i]))_;
ret=(1ll*ret+tmp)_;
}
return ret;
}
int main()
{
int P;
scanf("%d%d",&T,&P);
pre_prime(P);
while(T--){
init();
scanf("%d%d%d%d",&N,&N1,&N2,&M);
for(int i=1;i<=N1;i++) scanf("%d",&d[1<<(i-1)]);
for(int i=1,x;i<=N2;i++) scanf("%d",&x),M-=(x-1);
for(int s=1,p;p=s&-s,s<(1<<N1);s++)
h[s]=h[s^p]+1,k[s]=k[s^p]+d[p];
for(int s=0,m,tmp;s<(1<<N1);s++){
m=M-k[s];
tmp=exLucas(m-1,N-1,P);
if(h[s]&1) tmp=(-1ll*tmp+P)_;
ANS=((1ll*ANS+tmp)_+P)_;
}
printf("%d\n",ANS);
}
return 0;
}

●BZOJ 3129 [Sdoi2013]方程的更多相关文章

  1. [BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】

    题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 ...

  2. 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} ...

  3. BZOJ 3129 SDOI2013 方程

    如果没有限制,答案直接用隔板法C(m-1,n-1) 对于>=x的限制,我们直接在对应位置先放上x-1即可,即m=m-(x-1) 对于<=x的限制,由于限制很小我们可以利用容斥原理将它转化为 ...

  4. bzoj千题计划267:bzoj3129: [Sdoi2013]方程

    http://www.lydsy.com/JudgeOnline/problem.php?id=3129 如果没有Ai的限制,就是隔板法,C(m-1,n-1) >=Ai 的限制:m减去Ai &l ...

  5. bzoj3129[Sdoi2013]方程 exlucas+容斥原理

    3129: [Sdoi2013]方程 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 582  Solved: 338[Submit][Status][ ...

  6. 【BZOJ3129】[SDOI2013]方程(容斥,拓展卢卡斯定理)

    [BZOJ3129][SDOI2013]方程(容斥,拓展卢卡斯定理) 题面 BZOJ 洛谷 题解 因为答案是正整数,所先给每个位置都放一个就行了,然后\(A\)都要减一. 大于的限制和没有的区别不大, ...

  7. BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理

    BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理 Description 给定方程     X1+X2+. +Xn=M 我们对第l..N1个变量进行一些限制: Xl < = A ...

  8. bzoj 3129

    非常好的一道数学题,考察了大量数论和组合数学的知识 在做本题之前强烈建议先完成下列两个背景知识: ①: bzoj 2142礼物 因为本题的一部分数据需要利用到拓展卢卡斯定理,而礼物是拓展卢卡斯定理的裸 ...

  9. [BZOJ 3198] [Sdoi2013] spring 【容斥 + Hash】

    题目链接:BZOJ - 3198 题目分析 题目要求求出有多少对泉有恰好 k 个值相等. 我们用容斥来做. 枚举 2^6 种状态,某一位是 1 表示这一位相同,那么假设 1 的个数为 x . 答案就是 ...

随机推荐

  1. Python习题(第一课)

    想了想其他的太简单了,还是不放了,剩三题吧. 一.完美立方 编写一个程序,对任给的正整数N (N≤100),寻找所有的四元组(a, b, c, d),使得a^3= b^3 + c^3 + d^3,其中 ...

  2. Mac使用brew安装软件

    Homebrew官方网站:https://brew.sh/1,安装brew,Mac中打开Termal输入命令: /usr/bin/ruby -e "$(curl -fsSL https:// ...

  3. WPF自学入门(十一)WPF MVVM模式Command命令

    在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正如上一篇文章中在开始说的,MVVM的目的是为了最大限度地降低了 ...

  4. thinkphp中的常见静态常亮

    thinkphp __PUBLIC__的定义 __ROOT__等常量的定义 1 2 3 4 5 6 7 8 9 '__TMPL__'      =>  APP_TMPL_PATH,  // 项目 ...

  5. 自定义SpringBoot启动banner

    序: springboot启动的时候会有一个启动logo似的东西,如图,这个logo似的东西叫做banner,本文小计修改此banner显示与关闭banner.没什么用,有兴趣可以玩玩-- 正文: 自 ...

  6. openssl几个加密算法使用介绍

    1.openssl简介 1)openssl概述 OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法.常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用. ...

  7. LXC学习实践(1)LXC的概念和用途

    1.LXC是什么? LXC是Linux containers的简称,是一种基于容器的操作系统层级的虚拟化技术,Sourceforge上有LXC这个开源项目. 2.LXC能做什么? LXC和Linux内 ...

  8. gradle入门(1-4)多项目构建实战

    一.多项目构建 1.多项目构建概念 尽管我们可以仅使用单个组件来创建可工作的应用程序,但有时候更广泛的做法是将应用程序划分为多个更小的模块. 因为这是一个非常普遍的需求,因此每个成熟的构建工具都必须支 ...

  9. word2vec初探(用python简单实现)

    为什么要用这个? 因为看论文和博客的时候很常见,不论是干嘛的,既然这么火,不妨试试. 如何安装 从网上爬数据下来 对数据进行过滤.分词 用word2vec进行近义词查找等操作 完整的工程传到了我的gi ...

  10. 安卓手机USB共享网络给PC上网

    开端 哈哈,最近我又发现了一个校园网的漏洞,但是只能手机连接,于是就想手机连接之后通过usb共享给电脑上网. 在手机上连接校园网WiFi,开启USB网络共享并且连接电脑之后,却发现电脑十分的卡顿!CP ...