原文链接www.cnblogs.com/zhouzhendong/p/UOJ348.html

前言

第一次知道子集卷积可以自己卷自己。

题解

这是一道子集卷积模板题。

设 $sum[S]$ 表示点集 S 的点权和。

设 $f[S]$ 表示对点集 S 进行州区划分得到的答案,定义 $g[S]$ 在点集 S 合法时为 $(sum[S])^p$,不合法时为 0 。

$$f[S] = \frac{1}{(sum[S])^p}\sum_{T\subsetneq S} f[T]g[S-T]$$

这东西是个子集卷积的形式。

但是在卷的时候要调用自己。

那怎么办?

一边做子集卷积,一边得出新答案。

具体地:枚举一下集合大小 S ,每次通过之前的结果做卷积求出当前集合大小的所有集合的答案。

直接保留 FMT 后的结果,方便计算、降低时间复杂度。

具体细节见代码。

时间复杂度 $O(n^22^n)$ 。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=23,S=1<<21,mod=998244353;
const ULL Bmod=16ULL*mod*mod;
int Pow(int x,int y){
int ans=1;
for (;y;y>>=1,x=(LL)x*x%mod)
if (y&1)
ans=(LL)ans*x%mod;
return ans;
}
void Add(int &x,int y){
if ((x+=y)>=mod)
x-=mod;
}
void Del(int &x,int y){
if ((x-=y)<0)
x+=mod;
}
int n,m,s,p;
vector <int> e[N];
int w[N];
int cnt1[S],sum[S],f[S];
int g[N][N];
int u[N][S],v[N][S];
int check(int s){
static int vis[N],in[N],q[N],head,tail,x;
if (!s)
return 0;
clr(vis),clr(in);
int fir=-1;
For(i,0,n-1)
if (s>>i&1){
fir=i;
break;
}
head=tail=0;
q[++tail]=fir,vis[fir]=1;
while (head<tail){
x=q[++head];
for (auto y : e[x])
if (s>>y&1){
in[y]^=1;
if (!vis[y])
vis[y]=1,q[++tail]=y;
}
}
if (tail!=cnt1[s])
return 1;
For(i,0,n-1)
if (in[i])
return 1;
return 0;
}
void FMT(int *a){
For(i,0,n-1)
For(j,0,s-1)
if (j>>i&1)
Add(a[j],a[j^1<<i]);
}
void IFMT(int *a){
For(i,0,n-1)
For(j,0,s-1)
if (j>>i&1)
Del(a[j],a[j^1<<i]);
}
int main(){
n=read(),m=read(),p=read();
s=1<<n;
clr(g);
For(i,1,m){
int x=read()-1,y=read()-1;
e[x].pb(y),e[y].pb(x);
}
For(i,0,n-1)
w[i]=read();
For(i,0,s-1){
For(j,0,n-1)
if (i>>j&1){
cnt1[i]++;
sum[i]+=w[j];
}
f[i]=check(i);
sum[i]=Pow(sum[i],p);
if (f[i])
u[cnt1[i]][i]=sum[i];
}
For(i,0,n)
FMT(u[i]);
v[0][0]=1;
FMT(v[0]);
For(i,1,n){
For(k,0,s-1){
ULL tmp=0;
For(j,0,i-1){
tmp+=(LL)v[j][k]*u[i-j][k];
if (tmp>=Bmod)
tmp-=Bmod;
}
v[i][k]=tmp%mod;
}
IFMT(v[i]);
For(k,0,s-1)
if (cnt1[k]==i)
v[i][k]=(LL)v[i][k]*Pow(sum[k],mod-2)%mod;
else
v[i][k]=0;
FMT(v[i]);
}
IFMT(v[n]);
cout<<v[n][s-1]<<endl;
return 0;
}

  

UOJ#348. 【WC2018】州区划分的更多相关文章

  1. [UOJ#348][WC2018]州区划分

    [UOJ#348][WC2018]州区划分 试题描述 小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 ...

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

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

  3. [WC2018]州区划分

    [WC2018]州区划分 注意审题: 1.有序选择 2.若干个州 3.贡献是州满意度的乘积 枚举最后一个州是哪一个,合法时候贡献sum[s]^p,否则贡献0 存在欧拉回路:每个点都是偶度数,且图连通( ...

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

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

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

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

  6. uoj#348/洛谷P4221 [WC2018]州区划分(FWT)

    传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...

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

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

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

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

  9. LOJ2340 [WC2018] 州区划分 【FMT】【欧拉回路】

    题目分析: 这题是WC的题??? 令 $g[S] = (\sum_{x \in S}w_x)^p$ $h[S] = g[S]$如果$S$不是欧拉回路 $d[S] = \frac{f[S]}{g[All ...

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

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

随机推荐

  1. TODO springboot学习笔记

    学习中,是在是搞不懂是什么狗屎....

  2. spring boot项目能启动打包失败

    如题,项目本地可以正常启动.但是用 mvn clean package打包就失败! 事件原因如下: 一.pom.xml少packing元素 <groupId>com.sanyi</g ...

  3. 080、Weave Scope 容器地图(2019-04-28 周日)

    参考https://www.cnblogs.com/CloudMan6/p/7655294.html   Weave Scope 的最大特点是会自动生成一张 Docker 容器地图,让我们能够直接的理 ...

  4. SimMechanics/Second Generation倒立摆模型建立及初步仿真学习

    笔者最近捣鼓Simulink,发现MATLAB的仿真模块真的十分强大,以前只是在命令窗口敲点代码,直到不小心敲入simulink,就一发不可收拾.话说simulink的模块化建模确实方便,只要拖拽框框 ...

  5. Machine Learning 思维导图

    Feature Enigneering 经用 sns.distplot 测试 一个Series 做 StandardScaler().fit_transform(Seriese) 之前和之后的图形形状 ...

  6. 配置tensorflow和keras时教程及问题总结

    基本参数:(如何基本参数和我的电脑不一致,有可能会出意外的错误) 操作系统:Windows 10,64位 Anaconda版本:Python 3.6版本.关于Anaconda的介绍.安装及使用教程可查 ...

  7. 如何在submit上运行php文件

    一..把php加入到环境变量 二.在sublmie中新建编译系统 三.添加一下代码,修改成php当前的目录地址,保存在默认的路径下,命名为php.sublime-build { "cmd&q ...

  8. CentOS6.5 下在Nginx中添加SSL证书

    原文:https://www.cnblogs.com/wuling129/p/5039978.html 证书过期 ,更新证书,记录下 一.安装相关支持库:(未实践) yum -y install gc ...

  9. 【转】ContextLoaderListener和DispatcherServlet加载内容的区别

    一.ContextLoaderListener加载内容 二.DispatcherServlet加载内容 ContextLoaderListener和DispatcherServlet都会在Web容器启 ...

  10. Django ---- 框架简介

    MVC框架和MTV框架 mvc,全名是 Model View Controller, 是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Cont ...