P4221 [WC2018]州区划分 题解
题目描述
给出 \(n\) 个城市,\(m\) 条边,一个划分合法当且仅当所有划分中的点集和集合中点之间存在的边集所构成的图不构成欧拉回路且联通。
定义一个点集的值为

划分的总值为其中所有点集的值之积,求所有合法划分的值之和。
题目分析
看到数据范围以及题目描述,不难想到使用状压 dp 解决此问题,首先对于每种状态判断是否合法,再枚举当前总状态和最后一个加进来的状态。
设当前状态为 \(i\),枚举出的子集状态为 \(j\),保证其合法,状态集合大小记为 \(siz_i\),可以得到以下状态转移方程:
\(f_i=\sum_{i\bigcap j=j}f_j(\frac{siz_j}{siz_i})^p\)
时间复杂度为 \(O(3^n)\),还无法通过本题。
继续观察柿子,如果把后面的乘数拆开分别处理,一个放到等式左边,一个另起一个函数,就会发现这其实就是一个子集卷积,卷完左边后对于右边部分乘上逆元恢复就行。
还有一个问题,这个柿子中 \(f\) 会自己卷自己,不过发现卷积中只会用到比自己 1 的个数少的状态,只需要一边卷一边处理即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define N 35
#define ll long long
using namespace std;
ll e,head[50000],nex[50000],to[50000];
ll val[N],g[22][(1<<22)];
ll vis[N],f[22][(1<<22)];
ll inv[(1<<22)];
ll n;
const ll mod=998244353;
queue<ll> q;
ll qp(ll x,ll y){
ll ans=1;
while(y){
if(y&1) ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
void add(ll u,ll v){
to[++e]=v;nex[e]=head[u];head[u]=e;
to[++e]=u;nex[e]=head[v];head[v]=e;
}
bool jud(ll x){
if(x==0) return false;
while(q.size()) q.pop();
for(ll i=1;i<=n;i++) vis[i]=0;
for(ll i=1;i<=n;i++)if((1<<(i-1))&x){q.push(i);break;}
while(q.size()){
ll u=q.front();q.pop();if(vis[u])continue;vis[u]++;
for(int i=head[u];i;i=nex[i]){
int v=to[i];
if((1<<(v-1))&x && !vis[v]) q.push(v);
}
}
for(ll i=0;i<n;i++) if((1<<i)&x && !vis[i+1]) return true;
for(ll i=0;i<=n;i++){
if(x&(1<<i)){
int cnt=0;
for(ll j=head[i+1];j;j=nex[j]){
ll v=to[j];
if((1<<(v-1))&x) cnt++;
}
if(cnt%2) return true;
}
}
return false;
}
ll sum(ll x){
ll ans=0;
for(ll i=0;i<n;i++) if(x&(1<<i)) ans+=val[i+1];
return ans;
}
void fwt(ll *f,ll opt){
for(ll mid=1,R=2;R<=(1<<n);R<<=1,mid<<=1){
for(ll j=0;j<(1<<n);j+=R){
for(ll k=0;k<mid;k++){
if(opt==1) f[j+k+mid]=(f[j+k+mid]+f[j+k])%mod;
else f[j+k+mid]=(f[j+k+mid]-f[j+k]+mod)%mod;
}
}
}
}
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int main(){
ll m,p,u,v;
n=read();m=read();p=read();
for(ll i=1;i<=m;i++){
u=read();v=read();
add(u,v);
}
for(ll i=0;i<n;i++) val[i+1]=read();
for(ll i=0;i<(1<<n);i++){
if(jud(i)) g[__builtin_popcount(i)][i]=qp(sum(i),p);
inv[i]=qp(qp(sum(i),mod-2),p);
}
f[0][0]=1;fwt(f[0],1);
for(ll i=0;i<=n;i++) fwt(g[i],1);
for(ll i=1;i<=n;i++){
for(ll j=0;j<i;j++){
for(ll k=0;k<(1<<n);k++){
f[i][k]+=(f[j][k]*g[i-j][k])%mod;
f[i][k]%=mod;
}
}
fwt(f[i],-1);
for(ll j=0;j<(1<<n);j++){
if(__builtin_popcount(j)==i)f[i][j]=(f[i][j]*inv[j])%mod;
else f[i][j]=0;
}
if(i!=n)fwt(f[i],1);
}
cout<<f[n][(1<<n)-1];
}
P4221 [WC2018]州区划分 题解的更多相关文章
- P4221 [WC2018]州区划分 无向图欧拉回路 FST FWT
LINK:州区划分 把题目中四个条件进行规约 容易想到不合法当前仅当当前状态是一个无向图欧拉回路. 充要条件有两个 联通 每个点度数为偶数. 预处理出所有状态. 然后设\(f_i\)表示组成情况为i的 ...
- uoj#348/洛谷P4221 [WC2018]州区划分(FWT)
传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...
- [UOJ#348][WC2018]州区划分
[UOJ#348][WC2018]州区划分 试题描述 小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 ...
- [WC2018]州区划分(FWT,FST)
[WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...
- [WC2018]州区划分——FWT+DP+FST
题目链接: [WC2018]州区划分 题目大意:给n个点的一个无向图,点有点权,要求将这n个点划分成若干个部分,每部分合法当且仅当这部分中所有点之间的边不能构成欧拉回路.对于一种划分方案,第i个部分的 ...
- [WC2018]州区划分
[WC2018]州区划分 注意审题: 1.有序选择 2.若干个州 3.贡献是州满意度的乘积 枚举最后一个州是哪一个,合法时候贡献sum[s]^p,否则贡献0 存在欧拉回路:每个点都是偶度数,且图连通( ...
- [WC2018]州区划分(FWT)
题目描述 题解 这道题的思路感觉很妙. 题目中有一个很奇怪的不合法条件,貌似和后面做题没有什么关系,所以我们先得搞掉它. 也就是判断一个点集是否合法,也就是判断这个点集是否存在欧拉回路. 如果存在欧拉 ...
- Luogu4221 WC2018州区划分(状压dp+FWT)
合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...
- [WC2018]州区划分(状压,子集卷积)
[洛谷题面]https://www.luogu.org/problemnew/show/P4221 首先考虑判定一个子图是否合法: (1)连通:并查集判断即可. (2)没有欧拉回路:存在欧拉回路的条件 ...
- 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 ...
随机推荐
- EasyExcel · 填充Excel
原文地址 Demo地址 最简单的填充 模版 效果 对象 @Getter @Setter @EqualsAndHashCode public class FillData { private Strin ...
- Mysql高级1-存储引擎
一.Mysql体系结构 1.1.连接层 最上层是一个客户端和链接服务,主要完成一些类似于链接处理,授权认证,及相关的安全方案,服务器也会为安全接入的而每个客户端验证它所具有的操作权限 1.2.服务层 ...
- ubuntu 终端选中黏贴、自带截图
鼠标选中 -- 复制 鼠标中键 -- 粘贴 注意,在tmux中,这个操作需要加上 Shift 键. PrtSc:截图整个桌面保存到Pictures Ctrl + PrtSc:截图整个桌面到剪贴板 Sh ...
- Crawpy - 一款python写的网站目录扫描工具
国外网站看到的. 简贴一下谷歌翻译的介绍 是什么让这个工具与其他工具不同: 它被写入异步工作,允许达到最大限制.所以它非常快. 校准模式,自行应用过滤器 有一堆标志可以帮助你详细地模糊 给定状态代码和 ...
- Spark RDD惰性计算的自主优化
原创/朱季谦 RDD(弹性分布式数据集)中的数据就如final定义一般,只可读而无法修改,若要对RDD进行转换或操作,那就需要创建一个新的RDD来保存结果.故而就需要用到转换和行动的算子. Spark ...
- 简单对比一下 C 与 Go 两种语言
以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/U6jIT837x5Yxe6Ev1aMDsA 使用一个简单的计数程序将 ...
- 《最新出炉》系列入门篇-Python+Playwright自动化测试-15-playwright处理浏览器多窗口切换
1.简介 浏览器多窗口的切换问题相比大家不会陌生吧,之前宏哥在java+selenium系列文章中就有介绍过.大致步骤就是:使用selenium进行浏览器的多个窗口切换测试,如果我们打开了多个网页,进 ...
- api接口怎么使用
API接口的使用在当今的软件开发中非常普遍,它允许不同的应用程序或服务之间进行数据交换和功能交互.API接口使得开发人员能够将不同的系统或平台集成在一起,以实现更复杂的功能和应用.本文将详细介绍API ...
- API接口的技术的概念
当今互联网技术的发展越来越快,越来越多的网站和应用程序需要获取外部数据来提供更好的服务和用户体验,这就需要使用API接口.本文将会对API接口的概念.类型以及如何调用API接口进行简要介绍. 一.什么 ...
- 分享一个 SpringBoot + Redis 实现「查找附近的人」的小技巧
前言 SpringDataRedis提供了十分简单的地理位置定位的功能,今天我就用一小段代码告诉大家如何实现. 正文 1.引入依赖 <dependency> <groupId> ...