题目: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. 前端学习笔记之CSS浮动浅析

    很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...

  2. CentOS7.2 安装nginx-1.10.3

    nginx-1.10.3 下载nginx 检查是否安装了依赖库: [root@localhost ~]# rpm -q gcc gcc-4.8.5-11.el7.x86_64 [root@localh ...

  3. Solidity 官方文档中文版 3_安装Solidity

    基于浏览器的Solidity 如果你只是想尝试一个使用Solidity的小合约,你不需要安装任何东西,只要访问 基于浏览器的Solidity http://remix.ethereum.org/. 如 ...

  4. 通过FISH和下一代测序检测肺腺癌ALK基因融合比较

    ALK FISH探针是FDA批准的用于检测肺癌患者中ALK重排的方法,这些患者可能受益于ALK激酶抑制剂.FISH测定在技术上可能具有挑战性并且难以解释.已经有研究者提出以ALK免疫组织化学和下一代测 ...

  5. iframe与父页面传值

    最近做的项目中用到了不少iframe,而且需要实现: 从父页面获取iframe中某个元素的值或则从iframe页面获取其父页面上某个元素的值. 在网上查询了相关东西,后总结如下: (1)父页面获取if ...

  6. Spark 数据倾斜调优

    一.what is a shuffle? 1.1 shuffle简介 一个stage执行完后,下一个stage开始执行的每个task会从上一个stage执行的task所在的节点,通过网络传输获取tas ...

  7. JAVA基础知识详解

    1. JVM是什么 JVM是Java Virtual Mechine的缩写.它是一种基于计算设备的规范,是一台虚拟机,即虚构的计算机. JVM屏蔽了具体操作系统平台的信息(显然,就像是我们在电脑上开了 ...

  8. Angular4笔记——表单状态相关的属性

    表单状态字段(FromControl)touched和untouched用来判断用户是否访问过一个字段(也就是这个字段是否获取过焦点,如果获取过焦点,touched是true,untouched是fa ...

  9. [转]vim 退格键(backspace)不能用

    http://my.oschina.net/zhangdapeng89/blog/56593 1.去掉讨厌的有关vi一致性模式,避免以前版本的一些bug和局限    set nocompatible ...

  10. org.springframework.beans.factory.BeanCreationException: sqlSessionFactory

    sqlSessionFactory实例化错误 pom默认导入的jar包中存在低版本,导致实例化sqlSessionFactory错误,删除此jar包即可