很裸的子集反演模板题,套上一些莫名其妙的外衣。

先预处理每个集合是否合法,再作显然的状压DP。然后发现可以写成子集反演的形式,直接套模板即可。

子集反演可以看这里

子集反演的过程就是多设一维代表集合大小,再FMT处理集合并卷积。

然而我的FMT常数过大,而并卷积又可以用FWT实现,于是就写FWT了。(实际上就三行的区别)

 #include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,mod=;
int n,m,p,x,y,mp[N][N],w[N],fa[N],a[N],d[N],sm[<<N],sz[<<N],lg[<<N],f[N][<<N],g[N][<<N]; int pow(int a,int b){ return b== ? : (b== ? a : 1ll*a*a%mod); }
int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); } int ksm(int a,int b){
int res=;
for (; b; a=1ll*a*a%mod,b>>=)
if (b & ) res=1ll*res*a%mod;
return res;
} void init(){
rep(i,,n) lg[<<i]=i;
rep(S,,(<<n)-){
int t=S&-S,tot=;
sm[S]=sm[S^t]+w[lg[t]]; sz[S]=sz[S^t]+;
for (int i=S; i; i=i^(i&-i)) a[++tot]=lg[i&-i];
rep(i,,tot) fa[a[i]]=a[i],d[a[i]]=;
rep(i,,tot){
rep(j,,tot) if (mp[a[i]][a[j]]) d[a[i]]^=,fa[get(a[i])]=get(a[j]);
if (d[a[i]]) { g[sz[S]][S]=; break; }
}
int f=get(a[]);
rep(i,,tot) if (f!=get(a[i])){ g[sz[S]][S]=; break; }
}
rep(i,,(<<n)-) sm[i]=pow(sm[i],p),g[sz[i]][i]=1ll*g[sz[i]][i]*sm[i]%mod;
} void FMT(int a[],int n,int f){
for (int i=; i<n; i<<=)
rep(j,,n-) if (j&i) a[j]=(a[j]+1ll*f*a[j^i]+mod)%mod;
} void solve(){
f[][]=; FMT(f[],<<n,);
rep(i,,n) FMT(g[i],<<n,);
rep(i,,n){
rep(j,,(<<n)-) rep(x,,i-)
f[i][j]=(f[i][j]+1ll*f[x][j]*g[i-x][j])%mod;
FMT(f[i],<<n,-);
rep(j,,(<<n)-)
if (sz[j]==i) f[i][j]=1ll*f[i][j]*ksm(sm[j],mod-)%mod; else f[i][j]=;
FMT(f[i],<<n,);
}
FMT(f[n],<<n,-); printf("%d\n",f[n][(<<n)-]);
} int main(){
scanf("%d%d%d",&n,&m,&p);
rep(i,,m) scanf("%d%d",&x,&y),mp[x-][y-]=mp[y-][x-]=;
rep(i,,n-) scanf("%d",&w[i]);
init(); solve();
return ;
}

FMT(TLE)

FWT:

 #include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,mod=;
int n,m,p,x,y,mp[N][N],w[N],fa[N],a[N],d[N],sm[<<N],sz[<<N],lg[<<N],f[N][<<N],g[N][<<N]; int pow(int a,int b){ return b== ? : (b== ? a : 1ll*a*a%mod); }
int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); } int ksm(int a,int b){
int res=;
for (; b; a=1ll*a*a%mod,b>>=)
if (b & ) res=1ll*res*a%mod;
return res;
} void init(){
rep(i,,n) lg[<<i]=i;
rep(S,,(<<n)-){
int t=S&-S,tot=;
sm[S]=sm[S^t]+w[lg[t]]; sz[S]=sz[S^t]+;
for (int i=S; i; i=i^(i&-i)) a[++tot]=lg[i&-i];
rep(i,,tot) fa[a[i]]=a[i],d[a[i]]=;
rep(i,,tot){
rep(j,,tot) if (mp[a[i]][a[j]]) d[a[i]]^=,fa[get(a[i])]=get(a[j]);
if (d[a[i]]) { g[sz[S]][S]=; break; }
}
int f=get(a[]);
rep(i,,tot) if (f!=get(a[i])){ g[sz[S]][S]=; break; }
}
rep(i,,(<<n)-) sm[i]=ksm(sm[i],p),g[sz[i]][i]=1ll*g[sz[i]][i]*sm[i]%mod;
} void FWT(int a[],int n,int f){
for (int i=; i<=n; i<<=)
for (int j=; j<n; j+=i)
rep(k,j,j+(i>>)-)
a[k+(i>>)]=(1ll*a[k+(i>>)]+f*a[k]+mod)%mod;
} void solve(){
f[][]=; FWT(f[],<<n,);
rep(i,,n) FWT(g[i],<<n,);
rep(i,,n){
rep(j,,(<<n)-) rep(x,,i-)
f[i][j]=(f[i][j]+1ll*f[x][j]*g[i-x][j])%mod;
FWT(f[i],<<n,-);
rep(j,,(<<n)-)
if (sz[j]==i) f[i][j]=1ll*f[i][j]*ksm(sm[j],mod-)%mod; else f[i][j]=;
FWT(f[i],<<n,);
}
FWT(f[n],<<n,-); printf("%d\n",f[n][(<<n)-]);
} int main(){
scanf("%d%d%d",&n,&m,&p);
rep(i,,m) scanf("%d%d",&x,&y),mp[x-][y-]=mp[y-][x-]=;
rep(i,,n-) scanf("%d",&w[i]);
init(); solve();
return ;
}

[WC2018]州区划分(状压DP+FWT/FMT)的更多相关文章

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

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

  2. 【UOJ348】【WC2018】州区划分 状压DP FWT

    题目大意 给定一个\(n\)个点的无向图,对于每种 \(n\) 个点的划分\(\{S_1,S_2,\ldots,S_k\}\),定义它是合法的,当且仅当每个点都在其中的一个集合中且对于任何的\(i\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. xampp + windows 配置 memcache流程

    1.运行xampp服务,打开phpinfo查看信息,如下图: 从上到下,依次为 PHP版本:5.6: architecture:x86: TS:线程安全: vc11 2.牢记以上几个横线内容之后去下载 ...

  2. 【译】第六篇 Integration Services:初级工作流管理

    本篇文章是Integration Services系列的第六篇,详细内容请参考原文. 简介在前几篇文章中,我们关注使用增量加载方式加载数据.在本篇文章,我们将关注使用优先约束管理SSIS控制流中的工作 ...

  3. 在mac环境下用QT使用OpenGL,glut,glfw

    只需要在新建工程中.pro文件中添加: #opengl glut LIBS+= -framework opengl -framework glut 就可以使用glut了. 继续添加: ##glfw L ...

  4. Java编程思想 4th 第3章 操作符

    有了数据,还需要进行数据间的运算,因此Java中也有数据间运算的各种符号,书本称之为操作符,正确的翻译应该是运算符. Java中的运算符同C++相同,运算符同运算符对象构成表达式,表达式是运算对象及运 ...

  5. 基于NIO的同步非阻塞编程完整案例,客户端发送请求,服务端获取数据并返回给客户端数据,客户端获取返回数据

    这块还是挺复杂的,挺难理解,但是多练几遍,多看看研究研究其实也就那样,就是一个Selector轮询的过程,这里想要双向通信,客户端和服务端都需要一个Selector,并一直轮询, 直接贴代码: Ser ...

  6. python基础===一行 Python 代码实现并行(转)

    原文:https://medium.com/building-things-on-the-internet/40e9b2b36148 译文:https://segmentfault.com/a/119 ...

  7. 使用pandas把mysql的数据导入MongoDB。

    使用pandas把mysql的数据导入MongoDB. 首先说下我的需求,我需要把mysql的70万条数据导入到mongodb并去重, 同时在第二列加入一个url字段,字段的值和第三列的值一样,代码如 ...

  8. RocketMQ使用

    RocketMQ是阿里巴巴在2012年开源的分布式消息中间件,目前已经捐赠给Apache基金会,并于2016年11月成为 Apache 孵化项目. 中间件是一类连接软件组件和应用的计算机软件,它包括一 ...

  9. linux nat网络配置

    1. 2 . 3. BOOTPROTO = static ONBOOT=yes  #开启自动启用网络连接 IPADDR0=192.168.21.128  #设置IP地址 PREFIXO0=24  #设 ...

  10. MySQL学习笔记:计算机服务中找不到MySQL服务

    不知道什么原因,连接了远程服务器之后,本地服务就连接不上. 经排查,发现服务中的MySQL服务居然不见,一番搜索之后,在CMD中进入到MySQL安装目录的bin下执行以下语句: mysqld.exe ...