原文链接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. Qt: 执行cmd命令;

    QProcess p(NULL); p.setWorkingDirectory(szAppPath+"/database"); //指定工作路径,这个地方一定要设置: p.star ...

  2. idea中如何添加RunDashboard

    在微服务开发中,往往要同时启动多个服务,这时候使用Run控制台难免会出错,并且不方便管理,这里推荐一个功能Run Dashboard idea中打开Run Dashboard的方法如下 view &g ...

  3. 那些年我们一起追逐的多线程(Thread、ThreadPool、委托异步调用、Task/TaskFactory、Parallerl、async和await)

    一. 背景 在刚接触开发的头几年里,说实话,根本不考虑多线程的这个问题,貌似那时候脑子里也有没有多线程的这个概念,所有的业务都是一个线程来处理,不考虑性能问题,当然也没有考虑多线程操作一条记录存在的并 ...

  4. 五十六、linux 编程——UDP 编程模型

    56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...

  5. matlab 图像设置

    Matlab画图设置线宽和字号 既然这么多人来这里看过,我就多做点注释,方便大家参考. 下边这段代码不需要特别设置,只需要在plot语句之后插入即可. %plot your figure before ...

  6. Java中快捷键

    Fond表示字体 size表示字号 IDEA的基本配置 IDEA中常用的快捷键 Intellij IDEA基本快捷键 Ctrl+G 跳转到指定行 Ctrl+F4 关闭当前编辑页面 Ctrl+F 搜索 ...

  7. typescript + echarts-for-react 制作渐变柱状图, 提示[ts] 类型“Graphic”上不存在属性“LinearGradient”

    更新: 2019/03 无意间发现Graphic上已有 LinearGradient属性 

  8. 安装pandas报错(AttributeError: 'module' object has no attribute 'main')

    在pycharm中安装pandas出现报错:AttributeError: 'module' object has no attribute 'main', 刚开始以为是pip的版本太旧了,于是乎将其 ...

  9. linux服务器磁盘挂载操作

    具体操作是:先对磁盘进行格式化,格式化后挂载到需要的挂载点,最后添加分区启动表,以便下次系统启动随机自动挂载.1.首先查看系统中磁盘信息,命令为:fdisk -l; 2.找到未使用的磁盘,对其进行格式 ...

  10. day 25-1 接口类、抽象类、多态

    # 接口类:python 原生不支持# 抽象类:python 原生支持的 接口类 首先我们来看一个支付接口的简单例子 from abc import abstractmethod,ABCMeta #我 ...