容斥原理
容斥原理:
容斥原理是一种在知道所有集合之间的交,求集合之间的并的数学方法。(注:交即为两个集合之间相同的部分,记作
problem:
设
易知:
也就是:
(摘自 OI-Wiki)
不定方程非负整数解计数:
problem:
给定
solution:(by OI-Wiki)
对于这个问题,我们可以抽象出一个容斥模型:
1.全集:
2.集合:
3.属性:即为限制条件。
解即为
我们可以通过求这个解集的补集,并用全集减去补集即可。
易知解集的补集为:
贴个代码:
#include<bits/stdc++.h> #define int long long using namespace std; const int mod=1e9+7; int n,m,a[50],ans; int inv(int x); int c_zh(int x,int y); signed main(){ cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; for(int s=1;s<=(1<<n)-1;s++){ int cnt=0,sum=0; for(int i=0;i<n;i++){ if(s&(1<<i)){ sum+=a[n-i]+1; cnt++; } } int f=-1; if(cnt&1)f=1; ans=(ans+f*c_zh(n-1,m-sum-1+n)%mod+mod)%mod;//这里是因为将限制减掉后变成了 0 ,所以还要加上n。 } cout<<(c_zh(n-1,m-1+n)%mod-ans%mod+mod)%mod<<endl; return 0; } int fast_pow(int x,int y){ int ret=x%mod,res=1; while(y){ if(y&1)res*=ret; ret*=ret; res%=mod;ret%=mod; y>>=1; } return res; } int inv(int x){ return fast_pow(x,mod-2); } int c_zh(int x,int y){ if(y<0)return 0; int res=1; for(int i=1;i<=x;i++){ res=(res*((y-i+1)%mod))%mod;// 注意这个可能溢出 } for(int i=1;i<=x;i++){ res=(res*inv(i))%mod; } //cout<<"x: "<<x<<" y: "<<y<<" ans: "<<res<<endl; return res; }
错位排列:
problem:对于一个有
solution:
还是考虑使用全集 - 补集的方法去求解。
模型:
1.全集:
2.集合:
3.属性:
那么很容易发现
所以答案即为:
通过容斥原理以及组合数的定义,我们可以知道答案为(这里不再推式子):
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18157425
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步