题目链接

题目描述

给出 \(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]州区划分 题解的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. [WC2018]州区划分

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

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

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

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

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

  9. [WC2018]州区划分(状压,子集卷积)

    [洛谷题面]https://www.luogu.org/problemnew/show/P4221 首先考虑判定一个子图是否合法: (1)连通:并查集判断即可. (2)没有欧拉回路:存在欧拉回路的条件 ...

  10. 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 ...

随机推荐

  1. 2023-07-13:如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。 花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串 定义下面几条语

    2023-07-13:如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串. 花括号展开的表达式可以看作一个由 花括号.逗号 和 小写英文字母 组成的字符串 定义下面几条语 ...

  2. Kubernetes亲和性学习笔记

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是欣宸在学习Kubernetes调度器的 ...

  3. SwiftUI的认识与使用

      SwiftUI简介 SwiftUI是苹果推出的一个新的UI框架,它使用了声明的方式,通过视图,基础控件和布局控件来进行页面的开发. SwiftUI具有跨平台性,一份SwiftUI代码可以同时跑在i ...

  4. Lora简介

    断断续续接触lora已经有几年时间了,一直用lora来做点对点的传输,近来有朋友想通过Lora来做广播群发和群收管理,想通过低成本方式实现,sx1302几百的银子,成本有点高,尝试通过sx1278/L ...

  5. 抽象类 vs 接口【概念解析系列_2】【C# 基础】

    〇.前言 抽象类和接口的相似之处还是很多的,但是它们的侧重点不同,本文将简单梳理下. 一.简介与示例 1.1 抽象类 抽象类就是不能使用 new 方法进行实例化的类,即没有具体实例对象的类. 抽象类有 ...

  6. Nessus 10.5.3 漏洞扫描器的下载安装与卸载

    测试环境 Kali 2023.2 本教程使用脚本进行自动化安装.破解 文章地址:https://www.iculture.cc/software/pig=25546#wznav_7 偶然发现,特别好用 ...

  7. Hugging News #0814: Llama 2 学习资源大汇总 🦙

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  8. Qt开发思想探幽]QObject、模板继承和多继承

    @ 目录 [Qt开发探幽]QObject.模板继承和多继承 1. QObject为什么不允许模板继承: 2.如果需要使用QObject进行多继承的话,子对象引用的父类链至多只能含有一个QObject ...

  9. Redis系列21:缓存与数据库的数据一致性讨论

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  10. C++算法之旅、04 基础篇 | 第一章

    常用代码模板1--基础算法 - AcWing ios::sync_with_stdio(false) 提高 cin 读取速度,副作用是不能使用 scanf 数据输入规模大于一百万建议用scanf 快速 ...