【集训】组合计数
题单
不是自己写的,总结的
交换求和顺序:
- 给定序列
,求其所有区间的区间和:答案是 。
二项式定理:
常见组合恒等式:
先从
利用
相当于从
考察
从
常见模型:
有
将
如果不要求每组非空,考虑直接给每组都加一个,方案数为
求方程
如果再给出序列
相当于
如果要求
- DP:
表示前 个数和为 的方案数,转移用前缀和优化。 - 容斥:钦定
以内的限制不被满足,其余的不管,转化为要求 的情形。
求有多少长为
把左括号看成往右走,有括号看成往上走,那么这个就对应一条
路径一共有
我们在最后触碰的位置
这就是卡特兰数。
另一方面,从括号序列的角度,我们还能给出另一种递推式:枚举第一个左括号匹配的右括号的位置为
其中
卡特兰数
- 对角线不相交的情况下,将一个
条边的凸多边形区域分成三角形区域的方法数,即三角剖分的方案数。 - 一个大小为
的栈,依次入栈 ,但可以在任意时机出栈,问有多少种出栈序。 个节点的无标号有根二叉树的个数。
P2671 [NOIP2015 普及组] 求和
现在考虑一组中有
若枚举
现在我们把这个式子拆开(把括号打开)
第一个式子可以化简为
第二个式子可以化简为
第三个式子
比如考虑
也就是说,当
考虑
也就是说,当
以此类推,第三个式子可以化简为
对于第四个式子,我们可以考虑每个
当
当
以此类推,第四个式子可以化简为
整理一下,可得:
简单维护即可。
#include <bits/stdc++.h>
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(int i=(a);i>=(b);--i)
#define U unsigned
#define LL long long
using namespace std;
template<class T>
inline void read(T &a){ register U LL x=0,t=1; register char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') t=-1; ch=getchar();} while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } a=x*t;}
inline void print(LL x){if(x<0)putchar('-'),x=-x;if(x>9) print(x/10);putchar(x%10+'0');}
const int mod=10007;
const int maxn=1e5+5;
int n,m;
int a[maxn],b[maxn];
int s1[maxn][2],s2[maxn][2];
int ans;
void sovle(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) {
cin>>b[i];
s1[b[i]][i%2]++;
s2[b[i]][i%2]=(s2[b[i]][i%2]+a[i])%mod;
}
for(int i=1;i<=n;i++){
int y=b[i];
ans+=i*(s2[y][i%2]+a[i]*(s1[y][i%2]-2)%mod)%mod;
ans%=mod;
}
cout<<ans<<endl;
}
signed main(){
sovle();
return 0;
}
把同色,同奇偶性的放在一起考虑。设当前分离出来的这一组编号分别为
预处理
AT_abc266_g [ABC266G] Yet Another RGB Sequence
首先我们考虑把
题面即变为:求
此时,我们先把
再考虑把
故共有
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
ll a,b,c,d,ans;
ll poww(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll C(int n,int m){
if(m==0) return 1;
ll res=1;
for(int i=n;i>=n-m+1;i--)
res=res*i%mod;
for(int j=1;j<=m;j++)
res=res*poww(j,mod-2)%mod;
return res;
}
int main(){
cin>>a>>b>>c>>d;
a-=d,b-=d;
ans=C(c+d+b,b)*C(d+c,d)%mod*C(c+d+a,a)%mod;
cout<<ans<<endl;
return 0;
}
AT_abc240_g [ABC240G] Teleporting Takahashi
当
否则,考虑先算出将
不妨考虑两维的情况
扩展到三维,答案就是
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=998244353,N=2e7+5;
ll fac[N],ifac[N],n,X,Y,Z;
int ksm(int x,int y,int p=mod){
int ans=1;
for(int i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p;
return ans%p;
}
ll inv(int x,int p=mod){
return ksm(x,p-2,p)%p;
}
void add(ll &x,ll v){
x+=v;
if(x>=mod) x-=mod;
}
ll C(int x,int y){
if(x<y||y<0) return 0;
return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}
ll F(int m){
if((m+X+Y)%2!=0) return 0;
return 1ll*C(m,(m+X+Y)/2)*C(m,(m+X-Y)/2)%mod;
}
signed main(){
cin>>n>>X>>Y>>Z;
fac[0]=1;
for(int i=1;i<=n*2;i++) fac[i]=1ll*fac[i-1]*i%mod;
ifac[n*2]=inv(fac[n*2]);
for(int i=n*2-1;i>=0;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
ll ans=0;
for(int z=0;z<=n;z++)
if((z+Z)%2==0)
add(ans,1ll*F(n-z)*C(n,z)%mod*C(z,(z+Z)/2)%mod);
cout<<ans<<endl;
return 0;
}
容斥原理 & 二项式反演
如果有
具体地,我们枚举一个约束的集合
例:计算有多少个长为
如果各个约束之间本质相同,即钦定违反的集合
常见容斥模型:
-
有
个球排成一列,每个球可以染成 种颜色中的一种,相邻球的颜色不能相同,但是每种颜色至少出现一次,问方案数。 -
计算有多少个长为
的序列 满足: ,且对每个 有 ,其中 是给定的序列。
P10596 BZOJ2839 集合计数
给定
仍然是钦定。设
设
二项式反演得:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 7,mod = 1000000007;
int ksm(int a, int b, int md) {
int res = 1;
while(b) {
if(b & 1) res = res * a % md;
a = a * a % md;
b >>= 1;
}
return res % md;
}
int fac[N], infac[N];
int getc(int a, int b) {
return fac[a] % mod * infac[b] % mod * infac[a - b] % mod;
}
signed main() {
int n, k;
cin >> n >> k;
fac[0] = infac[0] = 1;
for(int i = 1; i < N; i ++) {
fac[i] = fac[i - 1] * i % mod;
infac[i] = ksm(fac[i], mod - 2, mod) % mod;
}
int ans = 0,p = getc(n, k);
n -= k;
for(int i = n; i >= 0; i --) {
if(i % 2 == 0)
ans = (ans + getc(n, i) % mod * (ksm(2ll, ksm(2ll, n - i, mod - 1), mod) - 1) % mod) % mod;
else
ans = (ans - getc(n, i) % mod * (ksm(2ll, ksm(2ll, n - i, mod - 1), mod) - 1) % mod + mod) % mod;
ans %= mod;
}
cout << (ans * p + mod) % mod << endl;
}
P4859 已经没有什么好害怕的了
给出
我们假设
容易得到
我们记
容易发现对于
那么存在
#include <bits/stdc++.h>
using namespace std;
const int N = 2000+5, P = 1e9+9;
long long n, k, a[N], b[N], l[N], f[N][N], fac[N], ifac[N], g[N];
long long C(int n, int m) {
return 1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;
}
long long power(long long x,long long y){
long long res = 1;
while(y){
if(y & 1)
res = res * x % P;
x = x * x % P;
y >>= 1;
}
return res;
}
int main(){
cin>>n>>k;
if ((n+k)&1) return puts("0"),0;
k = (n+k)/2;
ifac[0] = ifac[1] = fac[0] = fac[1] = 1;
for(int i = 1;i <= n;i++)
fac[i] = fac[i - 1] * i % P;
ifac[n] = power(fac[n],P - 2);
for(int i = n;i >= 1;i--)
ifac[i - 1] = ifac[i] * i % P;
for (int i = 1; i <= n; i++) cin>>a[i];
for (int i = 1; i <= n; i++) cin>>b[i];
sort(a+1, a+n+1);
sort(b+1, b+n+1);
int ll = 0;
for (int i = 1; i <= n; i++) {
while (ll < n && b[ll+1] < a[i]) ++ll;
l[i] = ll;
}
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
f[i][0] = f[i-1][0];
for (int j = 1; j <= i; j++)
f[i][j] = (1ll*f[i-1][j]+1ll*f[i-1][j-1]*max(0ll, l[i]-j+1)%P)%P;
}
for (int i = 0; i <= n; i++) g[i] = 1ll*f[n][i]*fac[n-i]%P;
int ans = 0;
for (int i = k; i <= n; i++)
if ((i-k)&1) (ans -= 1ll*C(i, k)*g[i]%P) %= P;
else (ans += 1ll*C(i, k)*g[i]%P) %= P;
cout<<(ans+P)%P<<endl;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!