UOJ#348. 【WC2018】州区划分
原文链接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】州区划分的更多相关文章
- [UOJ#348][WC2018]州区划分
[UOJ#348][WC2018]州区划分 试题描述 小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 ...
- [WC2018]州区划分——FWT+DP+FST
题目链接: [WC2018]州区划分 题目大意:给n个点的一个无向图,点有点权,要求将这n个点划分成若干个部分,每部分合法当且仅当这部分中所有点之间的边不能构成欧拉回路.对于一种划分方案,第i个部分的 ...
- [WC2018]州区划分
[WC2018]州区划分 注意审题: 1.有序选择 2.若干个州 3.贡献是州满意度的乘积 枚举最后一个州是哪一个,合法时候贡献sum[s]^p,否则贡献0 存在欧拉回路:每个点都是偶度数,且图连通( ...
- [WC2018]州区划分(FWT,FST)
[WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...
- P4221 [WC2018]州区划分 无向图欧拉回路 FST FWT
LINK:州区划分 把题目中四个条件进行规约 容易想到不合法当前仅当当前状态是一个无向图欧拉回路. 充要条件有两个 联通 每个点度数为偶数. 预处理出所有状态. 然后设\(f_i\)表示组成情况为i的 ...
- uoj#348/洛谷P4221 [WC2018]州区划分(FWT)
传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...
- [WC2018]州区划分(FWT)
题目描述 题解 这道题的思路感觉很妙. 题目中有一个很奇怪的不合法条件,貌似和后面做题没有什么关系,所以我们先得搞掉它. 也就是判断一个点集是否合法,也就是判断这个点集是否存在欧拉回路. 如果存在欧拉 ...
- Luogu4221 WC2018州区划分(状压dp+FWT)
合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...
- 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 ...
- [WC2018]州区划分(状压DP+FWT/FMT)
很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...
随机推荐
- Hadoop高可用集群
1.简介 若HDFS集群中只配置了一个NameNode,那么当该NameNode所在的节点宕机,则整个HDFS就不能进行文件的上传和下载. 若YARN集群中只配置了一个ResourceManager, ...
- 暑假第二弹:基于docker的hadoop分布式集群系统的搭建和测试
早在四月份的时候,就已经开了这篇文章.当时是参加数据挖掘的比赛,在计科院大佬的建议下用TensorFlow搞深度学习,而且要在自己的hadoop分布式集群系统下搞. 当时可把我们牛逼坏了,在没有基础的 ...
- design language
design language https://en.wikipedia.org/wiki/Design_language 设计语言(设计词汇)是一种超架构的方案和风格, 它用于指导产品组件或者架构配 ...
- spring整合mybatis,批量扫描mapper接口出现异常
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component c ...
- mysql 关联表修改数据
UPDATE t1 INNER JOIN t2 ON t1.c1=t2.c1 SET t1.c2=value WHERE t1`removed`=0 AND t2`removed`=0 AND t1 ...
- opencv中imgshow图像显示为灰色
1.图像数据类型是否正确 2.图像是否存在 3.在imgshow()语句下添加watkey();
- 417 事件、监听、jQuery、轮播手动
am:通用事件 a链接事件阻止默认行为 return false HTML元素大都包含了自己的默认行为,例如:超链接.提交按钮等.我们可以通过在绑定事件中加上return false来阻止它的默认行为 ...
- jmeter分布式测试教程和远程的代理机无法连接网络的问题解决方法
一.Jmeter分布式执行原理: 1.Jmeter分布式测试时,选择其中一台作为控制机(Controller),其它机器做为代理机(Agent). 2.执行时,Controller会把脚本发送到每台A ...
- Java基础 -- String,StringBuilder,StringBuffer三者的区别
结论 1-String,StringBuilder,StringBuffer 之间的区别主要是在两个方面,即运行速度和线程安全这两方面: 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:St ...
- java--序列化和反序列化
一.序列化 java序列化的过程是把对象转换为字节序列的过程 序列化的两种用途: 1)把对象的字节序列永久保存大搜硬盘上,通常存放到一个文件中 2)在网络上传送对象的字节序列 jdk中的序列化API: ...