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

先预处理每个集合是否合法,再作显然的状压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. JavaScript 实用技巧和写法建议

    1.前言 从大学到现在,接触前端已经有几年了,感想方面,就是对于程序员而言,想要提高自己的技术水平和编写易于阅读和维护的代码,我觉得不能每天都是平庸的写代码,更要去推敲,去摸索和优化代码,总结当中的技 ...

  2. Velocity VelocityEngine 支持多种loader 乱码问题

    最近升级团队的代码生成工具,此工具是velocity实现的. 之前习惯使用UTF-8编码,现在团队使用GBK. 所以遇到一种场景,模板文件使用UTF-8(习惯了所有任性),输出文件使用GBK(项目需要 ...

  3. hdu 5463 Clarke and minecraft

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5463 Clarke and minecraft Time Limit: 2000/1000 MS (J ...

  4. 洛谷 P4559: bzoj 5319: [JSOI2018]军训列队

    题目传送门:洛谷 P4559. 题意简述: 有 \(n\) 个学生,编号为 \(i\) 的学生有一个位置 \(a_i\). 有 \(m\) 个询问,每次询问编号在 \([l,r]\) 区间内的学生跑到 ...

  5. python网络编程--线程Semaphore(信号量)

    一:Semaphore(信号量) 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才 ...

  6. vue+vuex+axios+echarts画一个动态更新的中国地图

    一. 生成项目及安装插件 # 安装vue-cli npm install vue-cli -g # 初始化项目 vue init webpack china-map # 切到目录下 cd china- ...

  7. 树莓派指定静态IP

    1.备份并清空 interfaces 文件 cp /etc/network/interfaces /etc/network/interfaces.bak vi /etc/network/interfa ...

  8. Oracle 函数 “自动生成订单号”

    create or replace function get_request_code return varchar2 AS --函数的作用:自动生成订单号 v_mca_no mcode_apply_ ...

  9. java 多线程总结篇3之——生命周期和线程同步

    一.生命周期 线程的生命周期全在一张图中,理解此图是基本: 线程状态图 一.新建和就绪状态 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Jav ...

  10. Java标记接口

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...