最近碰见了一些互异关系容斥的题目,而这类题目往往要配合集合幂级数的一些技术使用,所以简单记记。

内容很杂,行文很乱,作者水平很低,酌情观看。

互异关系容斥

思想其实很基本,应用范围其实很广。

原论文

思想就是对于 \(x_i\neq x_j\) 这样的限制,经典对于限制的子集容斥是钦定违反 \(S\) 中的限制,容斥系数为 \((-1)^{|S|}\)。

那么违反 \(x_i\neq x_j\) 相当于 \(x_i=x_j\),这是一个相等关系,可以将图划分成若干个等价类进行考虑。

互异关系容斥的第一个思想便是:对于每一个等价类,求出它边集的容斥系数之和。

举个例子,假设我们现在对一张完全图 \(K_n\) 的边集施加了容斥。这样相当于这张图被划分成了若干个等价类。对于大小为 \(m\) 的等价类,我们实际上要求的是所有使等价类联通的边集 \(E\subseteq E_{K_m}\) 的 \((-1)^{|E|}\) 之和。

设 \(f_n=\sum_{E\subseteq E_{K_n}} (-1)^{|E|}=[n=1]\),求个 \(\ln\) 就是联通图的系数:

\[g_n=f_n-\sum_{i=1}^n {n-1 \choose i-1} g_i f_{n-i}
\]

归纳知:\(g_n=(-1)^{n-1} (n-1)!\)。

互异关系容斥的第二个思想就是:对于 \(\bigoplus_{i=1}^n x_i=c\) 这样一种限制,如果 \(x_i\) 关于 \(\oplus\) 运算逆元总是存在且唯一(如模素数的加法群),那么我们如果知道了 \(x_1,x_2\dots x_{n-1}\) 就可以唯一确定一个 \(x_n\)。

那么如果不限制 \(x_i\) 互不相同,满足上述限制的个数就是 \(V^{n-1}\),\(V\) 是 \(x_i\) 的值域大小。

限制 \(x_i\) 互不相同可以看看周子衡大佬的论文是如何解决的。

集合幂级数

了解甚浅……只会一些基本的应用。

首先 \(\text{FWT}\) 应用了线性变换关于各维独立的性质,相当于给每一维乘上了一个 \(2\times 2\) 的矩阵。

我们不仅要知道 \(\text{FWT}\) 对于每一维分别的影响,更要知道做完 \(\text{FWT}\) 后整体的结果是怎样的。

具体地:

\[\text{or-FWT}:g_S=\sum_{T\subseteq S} f_T\\
\text{or-IFWT}:g_S=\sum_{T\subseteq S} (-1)^{|S|-|T|} f_T\\
\text{and-FWT}:g_S=\sum_{S\subseteq T} f_T\\
\text{and-IFWT}:g_S=\sum_{S\subseteq T} (-1)^{|S|-|T|} f_T\\
\text{xor-FWT}:g_S=\sum_{S\subseteq T} (-1)^{|S \cap T|} f_T\\
\text{xor-IFWT}:g_S=\frac{1}{2^n}\sum_{S\subseteq T} (-1)^{|S \cap T|} f_T\\
\]

然后子集卷积定义了 \(n+1\) 个占位幂级数。我们对占位幂级数 \(\text{or-FWT}\) 后的结果可以上各种各样的多项式操作。这里的操作由于都不是复杂度瓶颈所以都可以 \(O(n^2)\) 递推。

\(\ln:g_n=f_n-\frac{1}{n}\sum_{i=1}^{n-1} g_i i f_{n-i}\)。需要保证常数项为 \(1\)。

\(\exp:g_n=\frac{1}{n}\sum_{i=1}^{n} f_i i g_{n-i}\)。需要保证常数项为 \(0\)。

\(\mathrm{inv}:g_n=\frac{1-\sum_{i=0}^{n-1} g_i f_{n-i}}{f_0}\)。需要保证常数项存在逆。

注意!对于 \(F^n\) 不要多项式 \(\ln\) 再 \(\exp\),可以直接递推:

\[G=F^n\Rightarrow G'=nF^{n-1} F' \Rightarrow FG'=nF^n F'\Rightarrow FG'=nGF'
\]

比较系数即可递推。\(n\) 可以是有理数,顺便实现了多项式开根。

[HNOI2011] 卡农

求从 \(1,2,3\dots 2^k-1\) 中选 \(n\) 个数满足异或和为 \(0\) 的方案数。

递推做法前人之述备矣。我们考虑上点科技。

做法一:互异关系容斥

具体参考原论文。

原论文里给的第二道例题允许空集。这里要求不含空集,我们可以上点容斥,利用递推/推式子容斥掉空集。

不过这样做感觉有点复杂?还不如直接递推。

做法二:集合幂级数

发现如果定义形式幂级数乘法为异或卷积,答案就是:\(\prod_{S\neq \emptyset}(1+x^S y)\) 的 \(y^n\) 项系数。

我们对于每一个式子手动 \(\text{xor-FWT}\) 后点乘起来然后手动 \(\text{xor-IFWT}\)。

具体参见 qwaszx 题解

QOJ 5827 异或图

给定一张图,\(\forall (u,v)\in E,b_u\neq b_v\),\(b_i\in [1,a_i]\),求 \(\mathrm{xor}_{i=1}^n b_i=c\) 的方案数。\(n\leq 15\)。

如果没有互异关系,那么可以直接数位 \(\text{DP}\)。具体地,如果有一位上界是 \(1\) 但填了 \(0\) 那么后面的位任选,相当于去掉了异或和的限制,可以直接算方案数。

现在对互异关系上容斥,求出每一个点子集的容斥系数,集合幂级数求个 \(\ln\) 就得到了点子集是连通块的容斥系数。

发现大小为奇数的连通块相当于替换成一个数的限制 \(\min_{i\in S} a_i\),偶数连通块直接给答案乘上 \(\min_{i\in S} a_i + 1\)。

于是设 \(f_{S,T}\) 表示奇数联通块的限制下标为 \(T\),\(\text{DP}\) 即可。

复杂度上界是 \(O(4^n)\),但跑不满,然而写 unordered_map 会被卡常,用 vector 存一下就可以了。

#include <cstdio>
#include <vector>
using namespace std;
template<typename T>
T read(){
char c=getchar();T x=0;
while(c<48||c>57) c=getchar();
do x=(x<<1)+(x<<3)+(c^48),c=getchar();
while(c>=48&&c<=57);
return x;
}
const int N=33,S=1<<15,LG=63,P=998244353;
typedef long long ll;
int n,m,rk;ll c;
ll a[N],lis[N];
bool ban[S];
int coe[S],pos[S];
void inc(int &x,int v){if((x+=v)>=P) x-=P;}
void dec(int &x,int v){if((x-=v)<0) x+=P;}
vector< pair<int,int> > f[S];
int tmp[S];
int suf[N][2];
bool sta[LG],vis[S];
int stk[S],tp;
void upd(int x,int val){
if(!vis[x]) vis[stk[tp++]=x]=1;
inc(tmp[x],val);
}
int main(){
n=read<int>();m=read<int>();c=read<ll>();
for(int i=0;i<n;++i) a[i]=read<ll>();
for(int i=0;i<m;++i){
int u=read<int>()-1,v=read<int>()-1;
ban[(1<<u)|(1<<v)]=1;
}
for(int i=1;i<(1<<n);i<<=1)
for(int j=0;j<(1<<n);j+=(i<<1))
for(int k=j;k<(j|i);++k) ban[k|i]|=ban[k];
for(int s=1;s<(1<<n);++s){
int lb=__builtin_ctz(s);
int _s=s^(1<<lb);
pos[s]=lb;
if(_s&&a[pos[_s]]<a[lb]) pos[s]=pos[_s];
coe[s]=!ban[s];
for(int _t=_s;;_t=(_t-1)&_s){
int t=_t|(1<<lb);
if(t!=s&&!ban[s^t]) dec(coe[s],coe[t]);
if(!_t) break;
}
}
f[0].emplace_back(0,1);
for(int s=1;s<(1<<n);++s){
int lb=__builtin_ctz(s);
int _s=s^(1<<lb);
tp=0;
for(int _t=_s;;_t=(_t-1)&_s){
int t=_t|(1<<lb);
for(auto [x,val]:f[s^t])
if(__builtin_parity(t)) upd(x|(1<<pos[t]),(ll)coe[t]*val%P);
else upd(x,(a[pos[t]]+1)%P*val%P*coe[t]%P);
if(!_t) break;
}
f[s].resize(tp);
for(int i=0;i<tp;++i){
int x=stk[i];
f[s][i]=make_pair(x,tmp[x]);
tmp[x]=0;vis[x]=0;
}
}
int res=0;
for(auto [s,val]:f[(1<<n)-1]){
rk=0;
for(int i=0;i<n;++i)
if(s>>i&1) lis[rk++]=a[i];
int ans=0;
for(int t=59;~t;--t){
suf[rk][0]=1;suf[rk][1]=0;
for(int i=rk-1;~i;--i){
sta[i]=lis[i]>>t&1;
if(sta[i]){
lis[i]^=(1ll<<t);
suf[i][0]=((1ll<<t)%P*suf[i+1][0]+(lis[i]+1)%P*suf[i+1][1])%P;
suf[i][1]=((1ll<<t)%P*suf[i+1][1]+(lis[i]+1)%P*suf[i+1][0])%P;
}
else{
suf[i][0]=(lis[i]+1)%P*suf[i+1][0]%P;
suf[i][1]=(lis[i]+1)%P*suf[i+1][1]%P;
}
}
int par=(c>>t&1),cur=1;
for(int i=0;i<rk;++i){
if(sta[i]){
ans=(ans+(ll)cur*suf[i+1][par])%P;
par^=1;
}
cur=(lis[i]+1)%P*cur%P;
}
if(par) break;
if(!t) ++ans;
}
res=(res+(ll)ans*val)%P;
}
printf("%d\n",res);
return 0;
}

互异关系容斥&集合幂级数小记的更多相关文章

  1. LOJ575. 「LibreOJ NOI Round #2」不等关系 [容斥,分治FFT]

    LOJ 思路 发现既有大于又有小于比较难办,使用容斥,把大于改成任意减去小于的. 于是最后的串就长成这样:<<?<?<??<<<?<.我们把一段连续的& ...

  2. hdu 4135 a到b的范围中多少数与n互质(容斥)

    Co-prime 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4135 input The first line on input contains ...

  3. 【bzoj4671】异或图(容斥+斯特林反演+线性基)

    传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: ...

  4. 51 nod 1439 互质对(Moblus容斥)

    1439 互质对 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 有n个数字,a[1],a[2],…,a[n].有一个集合,刚开 ...

  5. BZOJ4671 异或图(容斥+线性基)

    题意 定义两个结点数相同的图 \(G_1\) 与图 \(G_2\) 的异或为一个新的图 \(G\) ,其中如果 \((u, v)\) 在 \(G_1\) 与 \(G_2\) 中的出现次数之和为 \(1 ...

  6. BZOJ 4671 异或图 | 线性基 容斥 DFS

    题面 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中 ...

  7. 51Nod 1439:互质对(用莫比乌斯来容斥)

    有n个数字,a11,a22,…,ann.有一个集合,刚开始集合为空.然后有一种操作每次向集合中加入一个数字或者删除一个数字.每次操作给出一个下标x(1 ≤ x ≤ n),如果axx已经在集合中,那么就 ...

  8. bzoj 4671 异或图——容斥+斯特林反演+线性基

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 考虑计算不是连通图的方案,乘上容斥系数来进行容斥. 可以枚举子集划分(复杂度是O(Be ...

  9. bzoj 2839 集合计数 容斥\广义容斥

    LINK:集合计数 容斥简单题 却引出我对广义容斥的深思. 一直以来我都不理解广义容斥是为什么 在什么情况下使用. 给一张图: 这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致. 特点: ...

  10. bzoj2839: 集合计数 容斥+组合

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 523  Solved: 287[Submit][Status][Discuss] ...

随机推荐

  1. pip安装报错 cannot uninstall a distutils installed project

    sudo pip install --ignore-installed xxx 在安装jupyter notebook的时候,遇到了这个问题,于是上网搜索,搜到了靠谱答案github解决方案 sudo ...

  2. unity 普通项目转URP项目

    1.导入UniversalRP (PackageManager 导入)2.创建Pipeline Asset     creat-->Rendering-->UniversalRender ...

  3. PYinstall打包程序出现编码错误的解决 'utf-8' codec can't decode byte 0xce in position 171: invalid continuation b

    网上说,先执行,再打包 chcp 65001 试过没有用. 解决方案: 把import的包批量注释,然后寻找是import那个文件导致. 虽然注释会导致程序运行出错,但是打包才不管你能不能运行. 最后 ...

  4. Python第六章实验报告

    一.实验内容:<零基础学Python>第六章实例和实战,以及一道作业题 二.实验环境:IDLE Shell 3.9.7 三.实验目的和要求:掌握定义和调用函数.变量的作用域.匿名函数.参数 ...

  5. 提供离线chrome谷歌浏览器插件crx的网站有

    crx4:http://www.crx4.com/ 极简插件:https://chrome.zzzmh.cn/index 扩展迷:https://www.extfans.com/ 浏览器插件下载中心: ...

  6. 浅谈js防抖和节流

    防抖和节流是处理高频触发最常见的优化方式,对性能提升有很大的帮助. 防抖:将多次的高频操作优化为只在最后一次执行,应用场景如:输入框,只需在最后一次输入进行校验即可. 节流:保证每隔一段时间只执行一次 ...

  7. maui BlazorWebView+本地html (vue、uniapp等都可以) 接入微信sdk 开发 Android app

    首先添加微信sdk的绑定库 nuget 包:Chi.MauiBinding.Android.WeChat 项目地址:https://github.com/realZhangChi/MauiBindin ...

  8. Solr 入门配置

    大多数搜索引擎应用都必须具有某种搜索功能,问题是搜索功能往往是巨大的资源消耗,并且它们由于沉重的数据库加载而拖垮你的应用的性能.这就是为什么转移负载到一个外部的搜索服务器是一个不错的注意,Apache ...

  9. CZHA0黑客游戏

    一个自己开发的黑客游戏,里面用到了自研AC库 A0阶段: from ac import* from time import * from sys import * def printf(text): ...

  10. [C++STL教程]7.priority_queue优先队列入门学习!零基础都能听懂的教程

    不知不觉C++STL教程系列已经第7期了.之前我们介绍过:vector, queue, stack, set, map等等数据结构. 今天我们来学习一个新的stl容器:priority_queue优先 ...