NFLSOJ 1060 - 【2021 六校联合训练 NOI #40】白玉楼今天的饭(子集 ln)
由于 NFLSOJ 题面上啥也没有就把题意贴这儿了(
没事儿,反正是上赛季的题,你们非六校学生看了就看了,况且看了你们也没地方交就是了
题意:
- 给你一张 \(n\) 个点 \(m\) 条边的图 \(G=(V,E)\)。
- 要求有多少张子图 \(G'=(V',E')\) 满足 \(G'\) 是连通二分图。
- \(n\le 20,m\le\dfrac{n(n-1)}{2}\)
- 答案对 \(998244353\) 取模。
输入样例 #1:
3 3
1 2
1 3
2 3
输出样例 #1:
9
众所周知,这场比赛现场六校就我一个人打(
首先考虑 \(n\le 17\) 怎么做,也就是本题的 80 分做法,注意到二分图计数这个东西是不太好直接求的,因为它涉及点集和边集两个决策对象,而这两个决策对象之间没有直接关联,因此考虑换个求解方式,我们将每个二分图与给二分图每个顶点进行黑白染色的方案看作一个整体,也就是二分染色图的数量,这样我们可以枚举染黑的点集 \(B\) 和染白的点集 \(W\),这样点集显然就是 \(B\cup W\),边集的限制就变为了不能存在一条连接两个 \(B\) 中节点的边,也不能存在一条连接两个 \(W\) 中节点的边,而 \(B\) 与 \(W\) 之间的边可以随意选择,因此假设 \(c\) 为 \(B\) 与 \(W\) 之间的边数,\(f_S\) 以 \(S\) 中点为点集的二分染色图的数量,那么有 \(f_{B\cup W}=2^c\)。
接下来考虑求出 \(f_S\) 之后怎样求解答案,注意到对于一个连通图而言,假如它是一个二分图,那么它对应的染色方法必然恰有 \(2\) 种,也就是说,假设以 \(S\) 为点集的连通二分图数量为 \(x\),那么以 \(S\) 为点集的连通二分染色图的数量就是 \(2x\),因此我们只需要求出 \(g_S\) 表示以 \(S\) 为点集的连通二分染色图数量即可求出答案,怎么求呢?其实做过这题的同学思考到这一步应该比较有感觉了,我们考虑再设 \(h_S\) 表示以 \(S\) 为点集的不连通二分染色图数量,那么显然 \(g_S+h_S=f_S\),而 \(h_S\) 的转移是容易的,就设 \(S\) 为 \(x\) 中最小的元素,然后枚举 \(x\) 所在的连通块 \(x\in T\subsetneq S\),贡献为 \(g_Tf_{S\backslash T}\),简单枚举个子集即可,时间复杂度 \(3^n\)。
注:现场 80pts 的代码,部分变量名称可能与上面不符,同时为了卡常我在求解 \(h_S\) 那一步强制要求 \(S\) 中最大的元素(instead of 最小的元素)必须属于 \(T\),这样一旦不符合即可 break 掉:
const int MAXM=136;
const int MAXP=1<<17;
const int MOD=998244353;
int n,m,pw2[MAXM+5];
int f[MAXP+5],g[MAXP+5],tot[MAXP+5],ed[MAXP+5];
int high(int x){return 31-__builtin_clz(x);}
int main(){
// freopen("youmu.in","r",stdin);freopen("youmu.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=(pw2[0]=1);i<=m;i++) pw2[i]=pw2[i-1]*2%MOD;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),ed[(1<<u-1)|(1<<v-1)]++;
for(int i=0;i<n;i++) for(int j=0;j<(1<<n);j++) if(j>>i&1) ed[j]+=ed[j^(1<<i)];
for(int i=1;i<(1<<n);i++){
for(int j=i;j;j=(j-1)&i){
if(high(j)!=high(i)) break;
tot[i]=(tot[i]+pw2[ed[i]-ed[j]-ed[i^j]])%MOD;
}
} f[0]=1;int ans=0;
for(int i=1;i<(1<<n);i++){
int lb=high(i&(-i));
for(int j=i;j;j=(j-1)&i){
if(j>>lb&1) g[i]=(g[i]+2ll*f[j]*tot[i^j])%MOD;
} f[i]=(tot[i]-g[i]+MOD)%MOD;ans=(ans+f[i])%MOD;
// printf("%d %d %d\n",i,f[i],g[i]);
} printf("%d\n",ans);
return 0;
}
接下来考虑优化,首先是第一步求解 \(f_S\) 的优化,注意到在第一步中,\(B\) 与 \(W\) 之间的边的个数可以用 \(ed_{B\cup W}-ed_B-ed_W\) 来表示,其中 \(ed_S\) 表示 \(S\) 中边的个数,那么 \(f_S=\sum\limits_{B\cup W=S,B\cap W=\varnothing}2^{ed_S-ed_B-ed_W}=2^{ed_S}\sum\limits_{B\cup W=S,B\cap W=\varnothing}\dfrac{1}{2^{ed_B}2^{ed_W}}\),容易发现这东西是一个子集卷积的形式,可以 \(2^nn^2\) 做掉。
然后是第二步的优化,这东西现场看来无法优化,所以就没写正解。现在学了子集卷积之后看就很 easy 了,我们记集合幂级数 \(A(x)\) 中 \(x^S\) 前的系数表示以 \(S\) 为点集的连通二分图染色数量,同理 \(B(x)\) 则表示二分染色图的数量,那么不难发现这题中 \(A(x)\) 与 \(B(x)\) 的关系就相当于 P4841 [集训队作业2013]城市规划 中,带标号图的数量的 OGF 与带标号连通图的数量的 OGF 的关系一样,因此 \(B(x)=\sum\limits_{n\ge 0}\dfrac{A^n}{n!}\),其中乘法表示子集卷积,也就是说 \(B=\exp A\),因此 \(A=\ln B\),不难发现 \([x^S]B(x)=f_S\),因此求个子集 \(\ln\) 即可求出 \(A\),也就是上文中的 \(g_S\)。
时间复杂度就降到了 \(2^nn^2\)。
代码(后面附有两个比较强的样例,没错你没看错,样例 #1 就是这题的样例,样例 #2 就是这题的样例):
const int MAXN=20;
const int MAXM=190;
const int MAXP=1<<20;
const int MOD=998244353;
const int INV2=499122177;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n,m,ed[MAXP+5],ppc[MAXP+5],tmp[MAXN+5],inv[MAXN+5],res=0;
int f[MAXN+5][MAXP+5],g[MAXN+5][MAXP+5],pw2[MAXM+5],ipw2[MAXM+5];
void FWTor(int *a,int len,int type){
for(int i=2;i<=len;i<<=1)
for(int j=0;j<len;j+=i)
for(int k=0;k<(i>>1);k++)
a[(i>>1)+j+k]=(a[(i>>1)+j+k]+1ll*a[j+k]*type)%MOD;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=(inv[0]=inv[1]=1)+1;i<=n;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=(pw2[0]=ipw2[0]=1);i<=m;i++) pw2[i]=(pw2[i-1]<<1)%MOD,ipw2[i]=1ll*ipw2[i-1]*INV2%MOD;
for(int i=1;i<(1<<n);i++) ppc[i]=ppc[i&(i-1)]+1;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),ed[(1<<u-1)|(1<<v-1)]++;
for(int i=0;i<n;i++) for(int j=0;j<(1<<n);j++) if(j>>i&1) ed[j]+=ed[j^(1<<i)];
for(int i=0;i<(1<<n);i++) f[ppc[i]][i]=ipw2[ed[i]];
for(int i=0;i<=n;i++) FWTor(f[i],1<<n,1);
for(int i=0;i<=n;i++) for(int j=0;j<(1<<n);j++) for(int l=0;l<=i;l++)
g[i][j]=(g[i][j]+1ll*f[l][j]*f[i-l][j])%MOD;
for(int i=0;i<=n;i++) FWTor(g[i],1<<n,MOD-1);
for(int i=0;i<(1<<n);i++) for(int j=0;j<=n;j++) if(ppc[i]!=j) g[j][i]=0;
for(int i=0;i<(1<<n);i++)
g[ppc[i]][i]=1ll*g[ppc[i]][i]*pw2[ed[i]]%MOD;
// for(int i=0;i<(1<<n);i++) printf("%d %d\n",i,g[ppc[i]][i]);
for(int i=0;i<=n;i++) FWTor(g[i],1<<n,1);
for(int i=0;i<(1<<n);i++){
memset(tmp,0,sizeof(tmp));
for(int j=1;j<=n;j++){
tmp[j]=g[j][i];
for(int k=1;k<j;k++)
tmp[j]=(tmp[j]-1ll*k*tmp[k]%MOD*inv[j]%MOD*g[j-k][i]%MOD+MOD)%MOD;
} for(int j=1;j<=n;j++) g[j][i]=tmp[j];
} for(int i=0;i<=n;i++) FWTor(g[i],1<<n,MOD-1);
// for(int i=0;i<(1<<n);i++) printf("%d %d\n",i,g[ppc[i]][i]);
for(int i=1;i<(1<<n);i++) res=(res+1ll*g[ppc[i]][i]*INV2)%MOD;
printf("%d\n",res);
return 0;
}
/*1
Input:
4 5
1 2
2 4
1 3
1 4
2 3
Output:
26
*/
/*2
Input:
6 13
1 2
1 3
2 3
1 4
4 2
3 4
5 2
3 5
5 4
6 2
6 3
6 4
6 5
Output:
1866
*/
NFLSOJ 1060 - 【2021 六校联合训练 NOI #40】白玉楼今天的饭(子集 ln)的更多相关文章
- NFLSOJ 1072 - 【2021 六校联合训练 NOIP #1】异或(FWT+插值)
题面传送门 一道非常不错的 FWT+插值的题 %%%%%%%%%%%% 还是那句话,反正非六校的看不到题对吧((( 方便起见在下文中设 \(n=2^d\). 首先很明显的一点是这题涉及两个维度:异或和 ...
- 题解 nflsoj553 【六校联合训练 省选 #10】飞
题目链接 我们称"简要题意"给出的三个要求分别为"条件1","条件2","条件3". 条件3长得比较丑,考虑转化一下.把 ...
- 题解 nflsoj550 【六校联合训练 省选 #9】序列
题目链接 以下把值域(题面里的\(lim\))记做\(m\). 考虑求\(k\)的答案.考虑每个位置对答案的贡献,枚举位置\(i\),再枚举\(a[i]\)的值\(x\).设: \[ F(k)=\su ...
- 题解 nflsoj489 【六校联合训练 CSP #15】小D与随机
题目链接 考虑枚举好点的集合.此时要考虑的问题是如何填入\(1\sim n\)这些数使得恰好我们枚举到的这些点是好点,即:求出有多少种合法的填数方案. \(1\)号点一定是好点.那么除\(1\)号点外 ...
- HDU 5358(2015多校联合训练赛第六场1006) First One (区间合并+常数优化)
pid=5358">HDU 5358 题意: 求∑i=1n∑j=in(⌊log2S(i,j)⌋+1)∗(i+j). 思路: S(i,j) < 10^10 & ...
- 2017多校联合训练2—HDU6054--Is Derek lying?(思维题)
Is Derek lying? Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...
- 2017ACM暑期多校联合训练 - Team 7 1010 HDU 6129 Just do it (找规律)
题目链接 Problem Description There is a nonnegative integer sequence a1...n of length n. HazelFan wants ...
- HDU6336-2018ACM暑假多校联合训练4-1005-Problem E. Matrix from Arrays-前缀和
题意是给了一种矩阵的生成方式 让你求两个左边之间的矩阵里面的数加起来的和(不是求矩阵的值) 没看标程之前硬撸写了160行 用了前缀和以后代码量缩短到原来的1/3 根据规律可以推导出这个矩阵是在不断重复 ...
- 2016多校联合训练4 F - Substring 后缀数组
Description ?? is practicing his program skill, and now he is given a string, he has to calculate th ...
随机推荐
- 【c++ Prime 学习笔记】第10章 泛型算法
标准库未给容器添加大量功能,而是提供一组独立于容器的泛型算法 算法:它们实现了一些经典算法的公共接口 泛型:它们可用于不同类型的容器和不同类型的元素 利用这些算法可实现容器基本操作很难做到的事,例如查 ...
- HttpClient使用GET方式通过代理服务器读取页面的例子
import java.io.BufferedReader;import java.io.InputStreamReader;import org.apache.http.HttpEntity;imp ...
- OO第三单元
OO第三单元 JML语言理论基础,应用工具链 JML语言基础 JML简介 定义: JML 是一种形式化的. 面向 JAVA 的行为接口规格语言 作用: 开展规格化设计.这样交给代码实现人员的将不是可能 ...
- 微服务(五)nacos配置管理
1 统一配置管理 1.1 nacos中添加配置文件 注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要.基本不会变更的一些配置还是保存在微服务本地比较好. 1.2 从微服务拉取配置 微 ...
- sql 多表联合查询更新
sqlserver: update A a set a.i = b.k from B b where a.key = b.key oracle : update A a set a.i = (sele ...
- Openeuler安装完整man手册
Openeuler安装完整man手册 在 Debian 和 Ubuntu 中安装了Shell 前端软件包管理器apt(Advanced Packaging Tool),可以通过如下方式安装. ...
- 近期业务大量突增微服务性能优化总结-3.针对 x86 云环境改进异步日志等待策略
最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...
- clnt_create: RPC: Port mapper failure - Unable to receive: errno 111 (Connection refused)
clnt_create: RPC: Port mapper failure - Unable to receive: errno 111 (Connection refused) 关闭防火墙,可以连, ...
- Firefox火狐浏览器提示您的链接并不安全(解决办法)
火狐浏览器不管访问什么,一直提示连接不安全 解决办法: 1.在Firefox地址栏输入"about:config",回车,进入如下图页面 点击"我了解此风险" ...
- 谷粒 | 18 | Hystrix熔断器
Spring Cloud调用接口过程 Spring Cloud 在接口调用上,大致会经过如下几个组件配合: Feign ----->Hystrix ->Ribbon ->Http C ...