博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ4671 异或图
阅读量:5775 次
发布时间:2019-06-18

本文共 3358 字,大约阅读时间需要 11 分钟。

注意

线性基空间要开够,1左移超过31位应该写成1LL

前置芝士

斯特林反演

斯特林反演有两种形式(和二项式反演类似)

\[ G_n=\sum_{i=1}^n\left\{\begin{matrix}n\\i\end{matrix}\right\}F_i\Rightarrow F_n=\sum_{i=1}^n(-1)^{n-i}\left[\begin{matrix}n\\i\end{matrix}\right]G_i \]

\[ G_k=\sum_{i=k}^n\left\{\begin{matrix}i\\k\end{matrix}\right\}F_i\Rightarrow F_k = \sum_{i=k}^n(-1)^{i-k}\left[\begin{matrix}i\\k\end{matrix}\right]G_i \]

思路

利用第一种形式

\(g_i\)表示至少有i个连通块,用\(f_i\)表示恰好有i个联通块的方案数

首先\(ans=\sum_{i=1}^n T_i F_i\),先胡乱写一个式子,然后考虑\(T_i\)这个容斥系数到底是什么东西
每项被计算的次数是\(\left\{\begin{matrix}n\\i\end{matrix}\right\}\)
因为最后的答案中应该只包含1个连通块的贡献,所以可以得到一个式子
\[ \sum_{i=1}^n\left\{\begin{matrix}n\\i\end{matrix}\right\}T_i=\left[n=1\right] \]
斯特林反演一下有
\[ \sum_{i=1}^n\left[\begin{matrix}n\\i\end{matrix}\right][n=1]=T_n \]
所以
\[ T_i=(-1)^{n-i}(n-i)! \]

利用第二种形式

容易发现直接求并不好求,考虑反演一发

对于集合划分问题,一般都使用斯特林反演
\(g_i\)表示至少有i个连通块,用\(f_i\)表示恰好有i个联通块的方案数
对于\(g_i\)我们可以枚举一个子集的划分,不在同一个子集中的点之间一定没有边,在同一个子集中的点之间可以随意连边,这样就保证了如果划分了i个集合,那么最少会有i个连通块
接下来考虑系数,假设当前恰好划分出i个连通块,为了满足\(g_k\)的条件,相当于要把这i个连通块划分到k个新的连通块中,所以每个\(f_i\)会产生\(\left\{\begin{matrix}i\\k\end{matrix}\right\}\)的贡献
所以能够得到\(f_i\)\(g_i\)的关系
\[ g_k=\sum_{i=k}^n \left\{\begin{matrix}i\\k\end{matrix}\right\}f_i \]
根据斯特林反演公式
得到
\[ f_k=\sum_{i=k}^n(-1)^{i-k}\left[\begin{matrix}i\\k\end{matrix}\right]g_i \]
因为要求\(f_1\)
所以得到
\[ \begin{align}f_1&=\sum_{i=1}^n(-1)^{i-1}\left[\begin{matrix}i\\1\end{matrix}\right]g_i\\&=\sum_{i=1}^n(-1)^{i-1}(i-1)!g_i\end{align} \]

利用反演得出的柿子求解

第一种和第二种得出的式子是相同的,考虑如何计算\(G_i\)

dfs计算划分之后,把每个数都当成一个二进制数,确定每个图上没有那些边相连后,将其插入线性基中,最后求异或和为0的方案数,求异或和为零的方案数相当于要找到线性无关的组的个数,剩下的可以随便取,所以\(g_i=2^{n-t}\)t是线性无关的个数

代码

#include 
#include
#include
#define int long longusing namespace std;int n,T,has[100][20][20],belong[20],jd[100],nob,jc[40],ans=0;char s[200];void init(void){ nob=0; memset(jd,0,sizeof(jd));}void insert(int s){ for(int i=62;i>=1;i--){ if((s>>(i-1))&1LL){ if(!jd[i]){ nob++; jd[i]=s; break; } else s^=jd[i]; } }}void init_jc(void){ jc[0]=1; for(int i=1;i<=20;i++) jc[i]=(jc[i-1]*i);}void dfs(int num,int id){ // printf("%lld %lld\n",num,id); if(num==n){ init(); for(int i=1;i<=T;i++){ int S=0,mid=0; for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++){ mid++; if(belong[j]!=belong[k]){ S|=(1LL<<(mid-1))*has[i][j][k]; } } insert(S); } ans+=(((id-1)&1)?-1:1)*(jc[id-1])*(1LL<<(T-nob)); return; } for(int i=1;i<=id;i++){ belong[num+1]=i; dfs(num+1,id); belong[num+1]=0; } belong[num+1]=id+1; dfs(num+1,id+1); belong[num+1]=0;}signed main(){ init_jc(); scanf("%lld",&T); for(int i=1;i<=T;i++){ scanf("%s",s+1); int l=strlen(s+1); // printf("l=%d\n",l); if(!n) for(int j=1;;j++) if(j*(j-1)==2*l){ n=j; break; } int mid=1; for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++) has[i][j][k]=has[i][k][j]=s[mid++]-'0'; } dfs(0,0); printf("%lld\n",ans); return 0;}

转载于:https://www.cnblogs.com/dreagonm/p/10442086.html

你可能感兴趣的文章
Bug多,也别乱来,别被Bug主导了开发
查看>>
sed 替换基础使用
查看>>
高性能的MySQL(5)创建高性能的索引一B-Tree索引
查看>>
附件3:eclipse memory analyze使用教程
查看>>
oracle备份与恢复--rman
查看>>
图片变形的抗锯齿处理方法
查看>>
Effective C++ Item 32 确保你的 public 继承模子里出来 is-a 关联
查看>>
phpstorm安装laravel-ide-helper实现自动完成、代码提示和跟踪
查看>>
python udp编程实例
查看>>
TortoiseSVN中图标的含义
查看>>
js原生继承之——构造函数式继承实例
查看>>
linux定时任务的设置
查看>>
[CareerCup] 13.3 Virtual Functions 虚函数
查看>>
[Angular 2] ng-model and ng-for with Select and Option elements
查看>>
Tasks and Back stack 详解
查看>>
关于EXPORT_SYMBOL的作用浅析
查看>>
成功的背后!(给所有IT人)
查看>>
在SpringMVC利用MockMvc进行单元测试
查看>>
Nagios监控生产环境redis群集服务战
查看>>
Angular - -ngKeydown/ngKeypress/ngKeyup 键盘事件和鼠标事件
查看>>