题目大意

  给定一个\(n\)个点的无向图,对于每种 \(n\) 个点的划分\(\{S_1,S_2,\ldots,S_k\}\),定义它是合法的,当且仅当每个点都在其中的一个集合中且对于任何的\(i\in[1,k]\),点集\(S_i\)非空,且导出子图不存在欧拉回路。

  给定数组\(w_i\),求对于所有合法的划分\(\{s_1,s_2,\ldots,s_k\}\),下面的式子之和

\[{(\prod_{i=1}^k\frac{\sum_{x\in S_i}w_x}{\sum_{j=1}^i\sum_{x\in S_j}w_x})}^p
\]

  \(n\leq 21\)

题解

  先用\(O(n^22^n)\)判断每个点集是否合法,并计算\(g(S)={(\sum_{x\in S}w_x)}^p\)。如果\(S\)不合法。那么\(g(S)=0\)

  很容易想到一个\(O(3^n)\)的做法。

  设\(f(S)\)为当前选择的集合为\(S\)的答案

\[f(S)=\frac{\sum_{T\subseteq S}g(T) f(S\setminus T)}{g(S)}
\]

  可以发现这是一个子集卷积。

  一种可行的做法是把子集卷积转化为子集或卷积。

  定义\(\widetilde{f}\)是\(f\)的集合占位幂级数,当且仅当对于所有的\(S\)满足\(\widetilde{f}(S)\)是一个\(|S|\)次多项式,且\([x^{|S|}]\widetilde{f}(S)=f(S)\)

  可以发现,若\(p(S)=\widetilde f(S)\cdot \widetilde g(S)\),则\(p\)是\(f\times g\)的占位多项式。

  所以我们可以在\(O(n^22^n)\)内计算子集卷积了。

  回到这道题,我们假设每个城市可以出现在多个州里,记\(h_{i,S}\)为每个州的城市个数之和为\(i\),每个州的城市的并集为\(S\)的方案数。那么\(F(S)=\sum_{i=1}^nh_{i,S}x^i\)就是\(f(S)\)的集合占位幂级数。

  所以\(f(S)=h_{|S|,S}\),状态转移方程是

\[h_{i,S}=\sum_{j=1}^i\sum_{|T|=j}\sum_{A}[A|T=S]h_{i-j,A}\frac{g(T)}{g(S)}
\]

  记\(G(i)=\sum_{|S|=i}g(S)x^S\)

  我们先枚举\(i\),再枚举\(j\),然后计算\(h_i=h_{i-j}\times G(j)\)

  这里我们可以全程用莫比乌斯变换后的值,卷积一次就是\(O(2^n)\)的

  还有,我们这里要除以\(g(S)\),可以在做完一层(\(h_i\))之后变换回去,除以\(g(S)\),再变换回来。

  这样时间复杂度就是\(O(n^22^n)\)的了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
const ll p=998244353;
ll fp(ll a,ll b)
{
ll s=1;
for(;b;b>>=1,a=a*a%p)
if(b&1)
s=s*a%p;
return s;
}
int lx[100010];
int ly[100010];
int n,m,o;
void fwt(int *a)
{
int i,j;
for(j=1;j<1<<n;j<<=1)
for(i=0;i<1<<n;i++)
if(i&j)
a[i]=(a[i]+a[i^j])%p;
}
void ifwt(int *a)
{
int i,j;
for(j=1;j<1<<n;j<<=1)
for(i=0;i<1<<n;i++)
if(i&j)
a[i]=(a[i]-a[i^j])%p;
}
int f[22][1<<21];
int g[22][1<<21];
ll inv[100010];
ll fw[1<<21];
ll fwi[1<<21];
int w[30];
int fa[100010];
int num[1<<21];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int c[1<<21];
int d[100010];
int main()
{
open("walk");
int i,j,k;
inv[0]=inv[1]=1;
for(i=2;i<=10000;i++)
inv[i]=-p/i*inv[p%i]%p;
scanf("%d%d%d",&n,&m,&o);
for(i=1;i<=m;i++)
scanf("%d%d",&lx[i],&ly[i]);
for(i=1;i<=n;i++)
scanf("%d",&w[i]);
int all=(1<<n)-1;
for(i=1;i<=all;i++)
{
for(j=1;j<=n;j++)
{
d[j]=0;
fa[j]=j;
}
for(j=1;j<=m;j++)
if(((i>>(lx[j]-1))&1)&&((i>>(ly[j]-1))&1))
{
d[lx[j]]^=1;
d[ly[j]]^=1;
int fx=find(lx[j]);
int fy=find(ly[j]);
if(fx!=fy)
fa[fx]=fy;
}
fw[i]=0;
for(j=1;j<=n;j++)
if((i>>(j-1))&1)
fw[i]+=w[j];
fwi[i]=inv[fw[i]];
fw[i]=fp(fw[i],o);
fwi[i]=fp(fwi[i],o);
int cnt=0;
c[i]=0;
for(j=1;j<=n;j++)
if((i>>(j-1))&1)
{
num[i]++;
if(fa[j]==j)
{
cnt++;
if(cnt>=2)
c[i]=1;
}
if(d[j])
c[i]=1;
}
fw[i]*=c[i];
g[num[i]][i]=fw[i];
}
f[0][0]=1;
for(i=1;i<=n;i++)
fwt(g[i]);
fwt(f[0]);
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
for(k=0;k<=all;k++)
f[i][k]=(f[i][k]+(ll)f[i-j][k]*g[j][k])%p;
ifwt(f[i]);
for(j=0;j<=all;j++)
f[i][j]=f[i][j]*fwi[j]%p;
fwt(f[i]);
}
ifwt(f[n]);
ll ans=f[n][all];
ans=(ans+p)%p;
printf("%lld\n",ans);
return 0;
}

【UOJ348】【WC2018】州区划分 状压DP FWT的更多相关文章

  1. [WC2018]州区划分(状压DP+FWT/FMT)

    很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...

  2. UOJ348 WC2018 州区划分 状压DP、欧拉回路、子集卷积

    传送门 应该都会判欧拉回路吧(雾 考虑状压DP:设\(W_i\)表示集合\(i\)的点的权值和,\(route_i\)表示点集\(i\)的导出子图中是否存在欧拉回路,\(f_i\)表示前若干个城市包含 ...

  3. UOJ #348 州区划分 —— 状压DP+子集卷积

    题目:http://uoj.ac/problem/348 一开始可以 3^n 子集DP,枚举一种状态的最后一个集合是什么来转移: 设 \( f[s] \) 表示 \( s \) 集合内的点都划分好了, ...

  4. Luogu4221 WC2018州区划分(状压dp+FWT)

    合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...

  5. 集合划分状压dp

    给一个 $n$ 个点 $m$ 条边的无向图,每条边有 $p_i$ 的概率消失,求图连通的概率 $n \leq 9$ sol: 我们考虑一个 $dp$ $f_{(i,S)}$ 表示只考虑前 $i$ 条边 ...

  6. P4221 [WC2018]州区划分 无向图欧拉回路 FST FWT

    LINK:州区划分 把题目中四个条件进行规约 容易想到不合法当前仅当当前状态是一个无向图欧拉回路. 充要条件有两个 联通 每个点度数为偶数. 预处理出所有状态. 然后设\(f_i\)表示组成情况为i的 ...

  7. [WC2018]州区划分——FWT+DP+FST

    题目链接: [WC2018]州区划分 题目大意:给n个点的一个无向图,点有点权,要求将这n个点划分成若干个部分,每部分合法当且仅当这部分中所有点之间的边不能构成欧拉回路.对于一种划分方案,第i个部分的 ...

  8. [WC2018]州区划分(FWT,FST)

    [WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...

  9. [WC2018]州区划分(FWT)

    题目描述 题解 这道题的思路感觉很妙. 题目中有一个很奇怪的不合法条件,貌似和后面做题没有什么关系,所以我们先得搞掉它. 也就是判断一个点集是否合法,也就是判断这个点集是否存在欧拉回路. 如果存在欧拉 ...

随机推荐

  1. 我的微信小程序第三篇(app.json)

    前言 端午节回家了,所以好多天没有更新,只想说还是待在家里舒服呀,妈妈各种做好吃的,小侄子侄女各种粘着我在室外玩,导致我三天下来不仅胖了一圈,还黑了一圈,上班第一天有同事就说我晒黑了,哭~~~,为了防 ...

  2. 几何学观止(Lie群部分)

    上承这个页面,这次把Lie群的部分写完了 几何学观止-微分几何部分(20181102).pdf 我觉得其他部分(尤其是代数几何部分)我目前没有把握写得令自己满意,总之希望在毕业前能写完吧. 这次调整了 ...

  3. H5 video标签的属性

    35-video标签 video标签的属性 src: 用于告诉video标签需要播放的视频地址 autoplay: 用于告诉video标签是否需要自动播放视频 controls: 用于告诉video标 ...

  4. (第十三周)Final阶段成员贡献分

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 个人贡献分=基础分+表现分 基础分=5*5*0.5/5=2.5 成员得分如下: 成员 基础分 表现分 个人贡献 ...

  5. (Beta)团队贡献分

    Beta阶段团队每个成员都积极响应一起完成了开发, 所以最后我们一致决定各个成员的贡献分相同. 林珣玙 53 康家华 52 张启东 51 刘彦熙 49 马瑶华 48 仇栋民 47

  6. 福州大学软件工程1816 | W班 第10次作业[个人作业——软件产品案例分析]

    作业链接 个人作业--软件产品案例分析 评分细则 本次个人项目分数由两部分组成(课堂得分(老师/助教占比60%,学生占比40%)满分40分+博客分满分60分) 课堂得分和博客得分表 评分统计图 千帆竞 ...

  7. Jenkins Installing and migration

    JAVA_Zookeeper_hadoop - CSDN博客https://blog.csdn.net/wangmuming Installing Jenkins on Red Hat distrib ...

  8. Linux df 与du用法

    df 查看一级目录的大小,但是不能查看文件的大小.du 可以查看目录或者文件大小. 1 df的基本用法 df命令可以显示目前所有文件系统的总空间及当前可用空间,用法如下: -a 全部文件系统列表-h ...

  9. Linux中各个目录作用

    对于linux新手来说,最感到迷惑的问题之一就是文件都存在哪里呢?特别是对于那些从windows转过来的新手来说,linux的目录结构看起来有些奇怪哦.比如没有C盘,没有分盘符,一大堆不知道用途的文件 ...

  10. [转帖]Windows DHCPServer远程代码执行漏洞分析(CVE-2019-0626)

    Windows DHCPServer远程代码执行漏洞分析(CVE-2019-0626) ADLab2019-03-15共23605人围观 ,发现 4 个不明物体安全报告漏洞 https://www.f ...