UOJ 348 【WC2018】州区划分——子集卷积
参考: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】州区划分——子集卷积的更多相关文章
- [UOJ#348][WC2018]州区划分
[UOJ#348][WC2018]州区划分 试题描述 小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 ...
- [WC2018]州区划分
[WC2018]州区划分 注意审题: 1.有序选择 2.若干个州 3.贡献是州满意度的乘积 枚举最后一个州是哪一个,合法时候贡献sum[s]^p,否则贡献0 存在欧拉回路:每个点都是偶度数,且图连通( ...
- [WC2018]州区划分——FWT+DP+FST
题目链接: [WC2018]州区划分 题目大意:给n个点的一个无向图,点有点权,要求将这n个点划分成若干个部分,每部分合法当且仅当这部分中所有点之间的边不能构成欧拉回路.对于一种划分方案,第i个部分的 ...
- [WC2018]州区划分(FWT,FST)
[WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...
- uoj#348/洛谷P4221 [WC2018]州区划分(FWT)
传送门(uoj) 传送门(洛谷) 全世界都会子集卷积就咱不会--全世界都在写\(FMT\)就咱只会\(FWT\)-- 前置芝士 或运算\(FWT\)或者\(FMT\) 左转洛谷模板区,包教包会 子集卷 ...
- UOJ348 WC2018 州区划分 状压DP、欧拉回路、子集卷积
传送门 应该都会判欧拉回路吧(雾 考虑状压DP:设\(W_i\)表示集合\(i\)的点的权值和,\(route_i\)表示点集\(i\)的导出子图中是否存在欧拉回路,\(f_i\)表示前若干个城市包含 ...
- [WC2018]州区划分(状压,子集卷积)
[洛谷题面]https://www.luogu.org/problemnew/show/P4221 首先考虑判定一个子图是否合法: (1)连通:并查集判断即可. (2)没有欧拉回路:存在欧拉回路的条件 ...
- P4221 [WC2018]州区划分 无向图欧拉回路 FST FWT
LINK:州区划分 把题目中四个条件进行规约 容易想到不合法当前仅当当前状态是一个无向图欧拉回路. 充要条件有两个 联通 每个点度数为偶数. 预处理出所有状态. 然后设\(f_i\)表示组成情况为i的 ...
- bzoj5153 [Wc2018]州区划分
题目链接 正解:子集和变换. 考场上只会暴力和$p=0$的情况,还只会$O(2^{n}*n^{3})$的. 然而这题题面出锅,导致考场上一直在卡裸暴力,后面的部分分没写了..听$laofu$说$O(2 ...
随机推荐
- GOEXIF读取和写入EXIF信息
最新版本的gexif,直接基于gdi+实现了exif信息的读取和写入,代码更清晰. /* * File: gexif.h * Purpose: cpp EXIF reader * 3/2/2017 & ...
- HDU 3374 String Problem(最大最小表示+KMP)题解
题意:给你一个字符串,这个字符串可以这样操作:把第一个字符放到最后一个形成一个新的字符串,记原式Rank为1,每操作一步Rank+1,问你这样操作得出的最小字典序的字符串的Rank和这样的字符串有几个 ...
- CF_884_F(NetFlow)
codeforces_884_f 题目大意:给出一串长为n的字符串(保证n为偶数),定义反回文串为每一个位置的对应位置上的字母都不等于它(for each i : s[i] != s[n+1-i]), ...
- Easy install ryu
参考:Ubuntu14.04安装Ryu控制器 环境:Ubuntu 14.04 64bit 使用pip安装ryu: // dependencies sudo apt-get install Python ...
- linux find/grep 与cat联合使用
find ./ -name file_name.txt | xargs cat >> file_name.txt
- 日志_测试代码_Delphi7
1. 2.Delphi (Windows API 文件尾部添加) function LogFile(_str :string) :integer; var hFile :THandle; strFil ...
- [POI2012]ROZ-Fibonacci Representation (数学)
大意:给定n, 求至少要多少个斐波那契数相加减后能得到n (可以重复, 重复的算多次) 假设$dp(x)$为$x$的最小划分, 有$dp(x)=dp(x-F_k)+1$, 其中$F_k$为最接近$x ...
- 理解 Ruby Symbol (Ruby中的冒号)
http://blog.csdn.net/besfanfei/article/details/7966850 一直不明白:的作用 直到看到这篇文章 豁然开朗 处理符号相比字符串,占用更少的资源
- C++设计模式之中介者模式
中介者模式:用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互.中介者模式的例子很多,大到联合国安理会,小到房屋中介,都扮演了 ...
- IOS下使用多线程
ios有三种主要方法:1.NSThread.2.NSOperation.3.GCD. 1. NSThread: 调用方法如下:如果需要函数参数的话,可以通过Object传递. 1.1:[NSThre ...