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

先预处理每个集合是否合法,再作显然的状压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. 子查询优化--explain与profiling分析语句

    今天想的利用explain与progiling分析下语句然后进行优化.本文重点是如何通过explain与profiling分析SQL执行过程与性能.进而明白索引的重要性. 表的关系如下所示: 原始的查 ...

  2. Wannacry样本取证特征与清除

    一.取证特征 1)网络域名特征 http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com 2)文件特征 母体文件 mssecsvc.exe c: ...

  3. oracle 创建表空间 、用户 、赋权、建表

    一.创建表空间 1.创建临时表空间 create temporary tablespace TS_TEM_TAB_SPACE tempfile 'D:\oracle\TS_TEM_TAB_SPACE. ...

  4. select()函数用法三之poll函数

    poll是Linux中的字符设备驱动中有一个函数,Linux 2.5.44版本后被epoll取代,作用是把当前的文件指针挂到等待队列,和select实现功能差不多. poll()函数:这个函数是某些U ...

  5. getattr的使用

    from requests_html import HTMLSession class UrlGenerator(object): def __init__(self, root_url): self ...

  6. 06 Frequently Asked Questions (FAQ) 常见问题解答 (常见问题)

    Frequently Asked Questions (FAQ) Origins 起源 What is the purpose of the project? What is the history ...

  7. day04作业

    1.for(初始化表达式:条件表达式:循环后的操作表达式){ 循环体: } class Test_Sum { public static void main(String[] args) { int ...

  8. Eclipse 配置语言环境

    一.打开https://www.eclipse.org/babel/downloads.php 选择一下版本的Bable(通天塔) 选择 解压 打开Eclipse 软件 选择Help->inst ...

  9. 使用SQL语句查询某表中所有的主键、唯一索引以及这些主键、索引所包含的字段(转)

    SELECT 索引名称 = a.name , 表名 = c.name , 索引字段名 = d.name , 索引字段位置 = d.colid FROM sysindexes a JOIN sysind ...

  10. IdentityServer4揭秘---登录

    IdentityServer4默认提供了的登录地址是Account/Index 同意页面是Consent/Index 这里我们可以通过IdentittyServer4的用户交互自定义配置设置 在Con ...