题目:http://uoj.ac/problem/348

参考:https://www.cnblogs.com/NaVi-Awson/p/9242645.html#%E5%AD%90%E9%9B%86%E5%8D%B7%E7%A7%AF

FMT就是快速莫比乌斯变换/反演,解决或卷积的问题,和 FWT 时间复杂度一样。

FWT定义了 \( a'[i]=\sum\limits_{j|i=i}a[j] \) ,利用倍增算出 a'[ ] 作为点值,相乘之后再算回去; FMT 也定义了这样的东西,但计算 a'[ ] 的方法是高维前缀和。

高维前缀和大概就是一维一维独立做前缀和。把每个二进制位看成取值只有 0 , 1 的一个维度,这样的前缀和就是子集的和;所以这一位是 1 的时候就累计上其他位和自己一样、这一位是 0 的那些数的答案;可以想到每个子集会在枚举到最高的与自己不同的位(如果是从低位到高位枚举的)的时候被计入。

FMT 从 a'[ ] 变回 a[ ] 的方法就是把刚才加的那些位置都减回去。如果加的时候是从低位到高位枚举,此时应该从高位到低位枚举;但仍从低位到高位枚举也没问题,大概和 FWT 那里的想法一样。

修改一下 FMT ,就能求子集卷积了。

子集卷积与或卷积的不同在于或起来的那两个数不能有交。

这个限制就通过使那两个数的 1 的个数加起来正好等于自己的 1 的个数来解决。

a[ i ][ S ]表示 1 的个数为 i 、S 的答案;如果 S 的 1 的个数不为 i ,这个值就是 0 ; a'[ i ][ S ] 表示 1 的个数为 i 、S 的所有子集的答案。有 \( c'[i][S]=\sum\limits_{j=0}^{i}a'[j][S]*b'[i-j][S] \) 。

从 a[ i ][ S ] 到 a'[ i ][ S ] 就是对于这个 i 做一遍高维前缀和。从 a'[ i ][ S ] 到 a[ i ][ S ] 就是把高维前缀和倒过来做一遍。

这道题的式子是 \( dp[i][S]*w^p[i][S] = \sum\limits_{j=0 , T\subseteq S}^{i-1}dp[j][T]*w^p[i-j][S-T] \) ,好在算 dp[ i ] 的时候用到的 dp[ j ] 的 j<i ,所以把 i 放在最外层枚举即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=,K=(<<)+,mod=;
int n,m,p,hd[N],xnt,to[M],nxt[M];
int w[N][K],w2[K],dp[N][K],bin[N],ct[K];
bool ok[K],vis[N];
void upd(int &x){x>=mod?x-=mod:;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr,int fa,int s)
{
vis[cr]=;
for(int i=hd[cr],v;i;i=nxt[i])
if(!vis[v=to[i]]&&(s&bin[v-]))dfs(v,cr,s);
}
bool chk(int s)
{
for(int i=;i<=n;i++)
{
if(!(s&bin[i-]))continue; bool deg=;vis[i]=;
for(int j=hd[i];j;j=nxt[j])
if(s&bin[to[j]-])deg^=;
if(deg)return true;
}
int i;
for(i=;i<=n;i++)if(s&bin[i-]){dfs(i,,s);break;}
for(i++;i<=n;i++)if((s&bin[i-])&&!vis[i])return true;
return false;
}
void init()
{
bin[]=;for(int i=;i<=n;i++)bin[i]=bin[i-]<<;
for(int s=;s<bin[n];s++)ct[s]=ct[s-(s&-s)]+;///s from 1
for(int s=;s<bin[n];s++)ok[s]=chk(s);
}
void fmt(int *a,bool fx)
{
for(int i=;i<n;i++)
for(int s=;s<bin[n];s++)
if(s&bin[i])
(fx?a[s]+=mod-a[s^bin[i]]:a[s]+=a[s^bin[i]]),upd(a[s]);
}
int main()
{
n=rdn();m=rdn();p=rdn();
for(int i=,u,v;i<=m;i++)
u=rdn(),v=rdn(),add(u,v),add(v,u);
init();
for(int i=;i<=n;i++)w[][bin[i-]]=rdn();
for(int s=;s<bin[n];s++)w[ct[s]][s]=w[ct[s]-][s-(s&-s)]+w[][s&-s];
for(int s=;s<bin[n];s++)w[ct[s]][s]=pw(w[ct[s]][s],p);
for(int s=;s<bin[n];s++)w2[s]=pw(w[ct[s]][s],mod-);
for(int s=;s<bin[n];s++)if(!ok[s])w[ct[s]][s]=;//w2 is alright
dp[][]=;
for(int i=;i<=n;i++)
{
fmt(dp[i-],); fmt(w[i],);//i-j may =i
for(int j=;j<i;j++)
for(int s=;s<bin[n];s++)
dp[i][s]=(dp[i][s]+(ll)dp[j][s]*w[i-j][s])%mod;
fmt(dp[i],);
for(int s=;s<bin[n];s++)
if(ct[s]==i)dp[i][s]=(ll)dp[i][s]*w2[s]%mod;
else dp[i][s]=;
}
printf("%d\n",dp[n][bin[n]-]);
return ;
}

UOJ 348 【WC2018】州区划分——子集卷积的更多相关文章

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

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

  2. [WC2018]州区划分

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

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

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

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

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

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

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

  6. UOJ348 WC2018 州区划分 状压DP、欧拉回路、子集卷积

    传送门 应该都会判欧拉回路吧(雾 考虑状压DP:设\(W_i\)表示集合\(i\)的点的权值和,\(route_i\)表示点集\(i\)的导出子图中是否存在欧拉回路,\(f_i\)表示前若干个城市包含 ...

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

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

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

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

  9. bzoj5153 [Wc2018]州区划分

    题目链接 正解:子集和变换. 考场上只会暴力和$p=0$的情况,还只会$O(2^{n}*n^{3})$的. 然而这题题面出锅,导致考场上一直在卡裸暴力,后面的部分分没写了..听$laofu$说$O(2 ...

随机推荐

  1. poj2262 Goldbach's Conjecture

    poj2262 Goldbach's Conjecture 用欧拉筛把素数筛出来,再枚举一下. #include<iostream> #include<cstdio> #inc ...

  2. 20145221 《Java程序设计》课程总结

    20145221 <Java程序设计>课程总结 每周读书笔记链接汇总 Atom使用心得 - 21世纪的编辑器 网络安全攻防学习平台 - 基础关 Java实现:数据结构之排序 2014522 ...

  3. hyper-v安装虚拟机ubuntu 18.04 64bit后无法使能增强模式怎么办

    1.获取脚本来使能增强模式 $ sudo apt-get update $ sudo apt install git $ git clone https://github.com/jterry75/x ...

  4. 【转载】Java关键字之"transient"

    原文出处:http://blog.csdn.net/lanxuezaipiao/article/details/16358677 transient的作用及使用方法 我们都知道一个对象只要实现了Ser ...

  5. CentOS环境Docker安装教程(官方推荐的docker三种方式安装)

    CentOS环境Docker安装教程(官方推荐的docker三种方式安装) 一.使用yum方式安装 1.安装依赖包 $ sudo yum install -y yum-utils device-map ...

  6. python 随机整数

    # Program to generate a random number between and # import the random module import random print(ran ...

  7. Hadoop Ambari 安装

    ambari 1.2.4 下载地址:http://www.apache.org/dist/incubator/ambari/ambari-1.2.4/ambari-1.2.4-incubating.t ...

  8. 5G RRC——为NAS层提供连接管理,消息传递等服务; 对接入网的底层协议实体提供参数配置的功能; 负责UE移动性管理相关的测量、控制等功能

    from:http://www.cnblogs.com/kkdd-2013/p/3868676.html 1 RRC协议功能 为NAS层提供连接管理,消息传递等服务: 对接入网的底层协议实体提供参数配 ...

  9. vue触底,触顶事件

    data(){ return{ songList: [], //歌单列表 totalPage: "", total: "", pageSize: 10, thi ...

  10. vue router动态路由

    <div id="#app"> <router-link to="/user/header">路由1</router-link&g ...