容斥
容斥
本质的思想是,给集合里的元素标正负号,使得累加起来刚好抵消,得到所要的信息
特征:贡献大小可以抵消
例题


先考虑暴力怎么做,即确定一个合法的缩边顺序,然后再计算每个点上现在编号的出现次数
考虑怎么快速处理上述过程
钦定一个点\(RT\)是最后的点
即考虑子树的贡献怎么转移到父亲
需要处理,以某个子树为根,然后最后成为子树内某个编号的次数
然后在每一个多叉节点哪里转移一下
貌似就可以了
但多叉节点转移比较恶心
另一思考方向
进行一步转化:
初始树上没有边,每个节点权值为1,有一个长度\((n - 1)!\)的边集序列,依次加入这些边,每次加入一条边,让所连接的两个连通块的 权值 乘上 \(\frac{1}{2}\),显然有: 最后每个点身上的权值,就是在这个边集顺序下,留下来的概率
考虑如何解决
前置题目:[CTS2019] 氪金手游

考虑一条链
有k个反向边,就是K个容斥直接\(O(n^3)暴力算好了\)
#include<bits/stdc++.h>
#define MAXN 1005
typedef long long ll;
const ll mod = 998244353;
using namespace std;
int n;
ll a[MAXN][4];
int h[MAXN],tot;
struct node{int from,to,next;ll tp;}e[MAXN << 1];
void add(int x , int y , int z){
tot++;
e[tot].from = x;
e[tot].to = y;
e[tot].tp = z;
e[tot].next = h[x];
h[x] = tot;
}
ll poww(ll x , int y){
ll zz = 1;
while(y){
if(y & 1)zz = zz * x % mod;
x = x * x % mod;
y = y >> 1;
}
return zz;
}
int sz[MAXN];
ll f[MAXN][MAXN * 5],g[MAXN * 5];
void dfs(int now , int fa){
f[now][0] = 1;
for(int i = h[now] ; i != (-1) ; i = e[i].next){
if(e[i].to == fa)continue;
dfs(e[i].to , now);
memset(g , 0 , sizeof(g));
for(int j = 0 ; j <= sz[now] ; j++){
for(int k = 0 ; k <= sz[e[i].to] ; k++){
g[j + k] = (g[j + k] + f[now][j] * f[e[i].to][k] % mod * e[i].tp % mod) % mod;
if(e[i].tp != 1)g[j] = (g[j] + f[now][j] * f[e[i].to][k] % mod) % mod;
}
}
memcpy(f[now] , g , sizeof(g));
sz[now] += sz[e[i].to];
}
memset(g , 0 , sizeof(g));
for(int j = 0 ; j <= sz[now] ; j++){
for(int k = 1 ; k <= 3 ; k++){
g[j + k] = (g[j + k] + f[now][j] * k % mod * poww(j + k , mod - 2) % mod * a[now][k] % mod) % mod;
}
}
memcpy(f[now] , g , sizeof(g));
sz[now] += 3;
}
int main(){
memset(h , -1 , sizeof(h)) , tot = 0;
scanf("%d" , &n);int x,y;
for(int i = 1 ; i <= n ; i++){
ll sum = 0;
for(int j = 1 ; j <= 3 ; j++)scanf("%lld" , &a[i][j]) , sum += a[i][j];
sum = poww(sum , mod - 2);
for(int j = 1 ; j <= 3 ; j++)a[i][j] = a[i][j] * sum % mod;
}
for(int i = 1 ; i < n ; i++){
scanf("%d%d" , &x , &y);
add(x , y , 1);
add(y , x , mod - 1);
}
dfs(1 , 1);
ll ans = 0;
for(int i = 1 ; i <= 3 * n ; i++)ans = (ans + f[1][i]) % mod;
cout<<ans<<endl;
}
回到上一题
本质的思想是:首先钦定\(RT\),然后考虑加边的顺序
考虑加入\((RT,v)\) ,\(S为v所在的连通块\) ,那么现在 两个端点都在\(S\)里面的边,一定先选,
如果一个存在一个端点不在\(S\)里面,一定后选,且对答案产生\(\frac{1}{2}\)的贡献,并且可以继续递归
通过这样的一系列操作
可以得到边与边之间的偏序关系,并且可以DP
划定主动边与被动边
考虑\((u,v)的加入需要在(p,q)加入之后加入\),则连边\(( (u,v) ,(p,q) )\)
主动边与被动边连边
主动边与最近的主动边连接
即满足拓扑序
但这个玩意做出来是一个树形图
需要通过前面那个题的思想,容斥为一个内向森林
然后直接dp就好了
#include<bits/stdc++.h>
#define MAXN 65
typedef long double ll;
using namespace std;
int n,h[MAXN],tot;
struct node{int from,to,next;}e[MAXN << 1];
void add(int x , int y){
tot++;
e[tot].from = x;
e[tot].to = y;
e[tot].next = h[x];
h[x] = tot;
}
int sz[MAXN];
ll f[MAXN][MAXN],g[MAXN];
void dfs(int now , int fa){
sz[now] = f[now][0] = 1;
for(int i = h[now] ; i != (-1) ; i = e[i].next){
if(e[i].to == fa)continue;
dfs(e[i].to , now);
memset(g , 0 , sizeof(g));
for(int j = 0 ; j < sz[now] ; j++){
for(int k = 0 ; k < sz[e[i].to] ; k++){
g[j + k] = g[j + k] + f[now][j] * f[e[i].to][k] * (0.5 / (1.0 * (sz[e[i].to] - k)) - 1.0);
g[j + k + 1] += f[now][j] * f[e[i].to][k];
}
}
memcpy(f[now] , g , sizeof(g)) , sz[now] += sz[e[i].to];
}
}
int main(){
memset(h , -1 , sizeof(h)) , tot = 0;
scanf("%d" , &n);int x,y;
for(int i = 1 ; i < n ; i++)scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
for(int i = 1 ; i <= n ; i++){
memset(f , 0 , sizeof(f));
dfs(i , i);
ll ans = 1;
for(int j = h[i] ; j != (-1) ; j = e[j].next){
ll zz = 0;
for(int k = 0 ; k < sz[e[j].to] ; k++){
zz = zz + f[e[j].to][k] * 0.5 / (1.0 * (sz[e[j].to] - k));
}
ans *= zz;
}
cout<<setprecision(10)<<ans<<endl;
}
}

考虑容斥
之后直接dp做一下就好了(把二分图拉出来形成一条链)
或者
这种排列计数与 一张图构成双射,直接在这张图上计数就好了
AGC035F

考虑结果相同的情况
\(r_i = j,c_j = i - 1 \\ r_i = j - 1 , c_j = i\)
只有这两种情况相同
直接容斥即可


典中典了属于是
AGC036F

可以发现,每一个\(P_i\)都有一个合法上下界
并且合法上下界单减
考虑如何dp出\(f_k,至少k个位置不合法\)
之后的操作就比较高妙了
考虑\(lb_i\)全部为0,还是比较好做的
考虑容斥吧,强制至少有k个数满足\(p_i < lb_i\)
之后直接暴力dp一下就好了

先把所有\(R_i\)减去\(L_i\)
考虑对下界进行容斥,即每一个 \(A_i ? R_i-L_i\)
之间的关系
记当前的一个容斥下界为\(S\)
则一个值\(V\)的拼凑方案为
此时考虑不同的\(V\)可以一起转移,只要考虑\(V + aD^b\)在下界之外就好了
直接进行数位dp
有一个比较劣的做法
还是先把\(R_i减去L_i\)

浙公网安备 33010602011771号