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

试题描述

小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连。

现在小 \(S\) 要将这 \(n\) 座城市划分成若干个州,每个州由至少一个城市组成,每个城市在恰好一个州内。

假设小 \(S\) 将这些城市划分成了 \(k\) 个州,设 \(V_i\) 是第 \(i\) 个州包含的所有城市组成的集合。 定义一条道路是一个州的内部道路,当且仅当这条道路的两个端点城市都在这个州内。 如果一个州内部存在一条起点终点相同,不经过任何不属于这个州的城市,且经过这个州的每个城市至少一次、所有内部道路都恰好一次的路径(路径长度可以为 \(0\)),则称这个州是不合法的。

定义第 \(i\) 个州的满意度为:第 \(i\) 个州的人口在前 \(i\) 个州的人口中所占比例的 \(p\) 次幂,即:

\[\left( \frac{\sum_{x \in V_i} w_x}{\sum_{j=1}^i \sum_{x \in V_j} w_x} \right) ^p
\]

定义一个划分的满意度为所有州的满意度的乘积,求所有合法的划分方案的满意度之和,答案对 \(998244353\) 取模。

两个划分 \({V_1 \cdots V_k}\) 和 \({C_1 \cdots C_s}\) 是不同的,当且仅当 \(k \ne s\) ,或存在某个 \(1 \le i \le k\) ,使得 \(V_i \ne C_i\)。

输入

从标准输入读入数据。

输入第一行包含三个整数 \(n,m,p\),表示城市个数、城市之间的道路个数以及题目描述中的常数 \(p\);

接下来 \(m\) 行,每行两个正整数 \(u,v\),描述一条无向的道路,保证无重边无自环;

输入第 \(m+2\) 行有 \(n\) 个正整数,第 \(i\) 个正整数表示 \(w_i\)。

输出

输出到标准输出。

输出一行一个整数表示答案在模 \(998244353\) 意义下的取值。

即设答案化为最简分式后的形式为 \(\frac{a}{b}\) ,其中 \(a\) 和 \(b\) 互质。输出整数 \(x\) 使得 \(bx \equiv a \mod 998244353\) 且 \(0 \le x < 998244353\)。可以证明这样的整数 \(x\) 是唯一的。

输入示例1

  1. 3 2 1
  2. 1 2
  3. 2 3
  4. 1 1 1

输出示例1

  1. 1

输入示例2 & 输出示例2

样例数据下载

数据规模及约定

保证对于所有数据有:\(0 \le n \le 21\),\(0 \le m \le \frac{n \times (n−1)}{2}\),\(0 \le p \le 2\),\(1 \le w_i \le 100\)。

测试点 \(1 \sim 5\):\(n \le 15\),每个测试点 \(10\) 分;

测试点 \(7 \sim 9\):\(n\le 21,p=0\),每个测试点 \(5\) 分;

测试点 \(10 \sim 13\):\(n \le 21,p=1\),每个测试点 \(5\) 分;

测试点 \(14 \sim 15\):\(n \le 21,p=2\),每个测试点 \(5\) 分。

其实 OJ 上每个点分数都一样……

题解

还是从暴力 dp 入手。

令 \(f(S)\) 表示划分集合 \(S\) 中的城市的所有方案的满意度之和,那么转移就是

\[f(S) = \sum_{tS \subset S} { f(tS) \cdot h(S - tS) \cdot \left( \frac{sum(S - tS)}{sum(S)} \right) ^p }
\]

\(h(S)\) 表示集合 \(S\) 是否能够成为一个州,能的话值为 \(1\),否则值为 \(0\);\(sum(S)\) 表示集合 \(S\) 的人口数目总和。

接下来我们可以朝着 FWT 的方向去想,不难发现要保证 \(tS \subset S\) 这个条件就是做一个或卷积;但是我们并不能保证每个元素都和与它无交集的元素进行卷积,这时候就需要一个处理,我们给状态加一维。

令 \(f(i, S)\) 表示所有州的城市个数总和为 \(i\),所有州城市的并集为 \(S\) 的划分方案满意度之和。注意,这里的州之间是可以有交集的。

那么现在就可以进行或卷积了,转移方程如下(令 \(A\) 表示全集):

\[f(i, S) = \sum_{j=1}^i \sum_{S_1=0}^A \sum_{S_2=0}^A [S_1 \cup S_2 = S] \cdot [|S_2| = j] \cdot h(S_2) \cdot f(i-j, S_1) \cdot \left( \frac{sum(S_2)}{sum(S)} \right) ^p \\
f(i, S) \cdot sum(S)^p = \sum_{j=1}^i \sum_{S_1=0}^A \sum_{S_2=0}^A [S_1 \cup S_2 = S] \cdot ( [|S_2| = j] \cdot h(S_2) \cdot sum(S_2)^p ) \cdot f(i-j, S_1)
\]

令 \(g(j, S_2) = [|S_2| = j] \cdot h(S_2) \cdot sum(S_2)^p\),上面的式子就变成标准的或卷积形式了。

而且这样处理并不会因为州之间有交集而导致不能得到正确答案,当 \(i = |S|\) 的时候,\(f(i, S)\) 恰好是符合题意的答案。所以最终答案就是 \(f(n, A)\)。

我们如果在卷积的过程中一直保留点值(即不 IFWT 回去),就可以做到 \(2^n\) 的卷积,这样复杂度就是 \(O(n^2 \cdot 2^n)\) 的了。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cctype>
  6. #include <algorithm>
  7. using namespace std;
  8. #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
  9. #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
  10. int read() {
  11. int x = 0, f = 1; char c = getchar();
  12. while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
  13. while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
  14. return x * f;
  15. }
  16. #define maxn 22
  17. #define maxm 500
  18. #define maxs 2097152
  19. #define MOD 998244353
  20. #define pii pair <int, int>
  21. #define x first
  22. #define y second
  23. #define mp(x, y) make_pair(x, y)
  24. #define LL long long
  25. int n, m, p, w[maxn], cnt[maxn], can[maxs], sbit[maxs], inv[maxs], f[maxn][maxs], g[maxn][maxs];
  26. pii es[maxm];
  27. int fa[maxn];
  28. int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); }
  29. int Pow(int a, int b) {
  30. int ans = 1, t = a;
  31. while(b) {
  32. if(b & 1) ans = (LL)ans * t % MOD;
  33. t = (LL)t * t % MOD; b >>= 1;
  34. }
  35. return ans;
  36. }
  37. void FWT_or(int *a, int len, int tp) {
  38. int n = 1 << len;
  39. rep(i, 1, len) for(int j = 0; j < n; j += 1 << i) rep(k, 0, (1 << i >> 1) - 1) {
  40. int la = a[j+k], ra = a[j+k+(1<<i>>1)];
  41. if(tp > 0) {
  42. a[j+k] = (la + ra) % MOD;
  43. a[j+k+(1<<i>>1)] = la;
  44. }
  45. else {
  46. a[j+k] = ra;
  47. a[j+k+(1<<i>>1)] = (la - ra + MOD) % MOD;
  48. }
  49. }
  50. return ;
  51. }
  52. int main() {
  53. n = read(); m = read(); p = read();
  54. rep(i, 1, m) {
  55. int a = read() - 1, b = read() - 1;
  56. es[i] = mp(a, b);
  57. }
  58. rep(i, 0, n - 1) w[i] = read();
  59. int all = (1 << n) - 1;
  60. rep(s, 1, all) {
  61. int c = 0, cbit;
  62. rep(i, 0, n - 1) if(s >> i & 1) sbit[s] += w[i], c++;
  63. cbit = c;
  64. inv[s] = Pow(sbit[s], MOD - 2);
  65. rep(i, 0, n - 1) fa[i] = i, cnt[i] = 0;
  66. rep(i, 1, m) if((s >> es[i].x & 1) && (s >> es[i].y & 1)) {
  67. int u = findset(es[i].x), v = findset(es[i].y);
  68. if(u != v) fa[v] = u, c--;
  69. cnt[es[i].x]++; cnt[es[i].y]++;
  70. }
  71. bool has = 0;
  72. rep(i, 0, n - 1) if(s >> i & 1) has |= cnt[i] & 1;
  73. if(has || c > 1) can[s] = 1, g[cbit][s] = Pow(sbit[s], p);
  74. }
  75. f[0][0] = 1;
  76. FWT_or(f[0], n, 1);
  77. rep(i, 0, n) FWT_or(g[i], n, 1);
  78. rep(i, 1, n) {
  79. rep(j, 1, i) rep(k, 0, all) (f[i][k] += (LL)g[j][k] * f[i-j][k] % MOD) %= MOD;
  80. FWT_or(f[i], n, -1);
  81. rep(k, 0, all) f[i][k] = (LL)f[i][k] * Pow(inv[k], p) % MOD;
  82. if(i < n) FWT_or(f[i], n, 1);
  83. }
  84. printf("%d\n", f[n][all]);
  85. return 0;
  86. }

[UOJ#348][WC2018]州区划分的更多相关文章

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

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

  2. [WC2018]州区划分

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

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

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

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

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

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

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

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

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

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

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

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

  9. [WC2018]州区划分(状压DP+FWT/FMT)

    很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...

随机推荐

  1. django+xadmin在线教育平台(十二)

    6-4 用form实现登录-1 上面我们的用户登录的方法是基于函数来做的.本节我们做一个基于类方法的版本. 要求对类的继承有了解. 基础教程中基本上都是基于函数来做的,其实更推荐基于类来做.基于类可以 ...

  2. 「译」setState如何知道它该做什么?

    本文翻译自:How Does setState Know What to Do? 原作者:Dan Abramov 如果有任何版权问题,请联系shuirong1997@icloud.com 当你在组件中 ...

  3. Shell学习——数组

    1.普通数组:只能用整数作为索引1.1.赋值[root@client02 ~]# array[0]=test1[root@client02 ~]# array[1]=test2[root@client ...

  4. 【shell脚本学习-1】

    Shell学习笔记 简介: Shell 是一个用C语言编写的程序,它是用户使用Linux的桥梁.Shell既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这个应用程序提供了一个 ...

  5. HTML+CSS : 笔记整理(3 移动端布局简单了解)

    流体布局:宽度用百分比,计算真实宽度用函数 : width: calc(25% - 4px); box-sizing: 1.content-box:默认计算方式 ,宽度和高度分别应用到元素的内容框.在 ...

  6. flask-login原理详解

    最近发现项目中使用的flask-login中有些bug,直接使用官网的方式确实可以用,但仅仅是可以用,对于原理或解决问题没有什么帮助,最近通过查看网上资料.分析源码.通过demo.从零开始总结了fla ...

  7. LAMP架构的搭建

    什么是LAMP架构? L : Linux,2.6.18-308.el5(redhat5.8) A :Apache,httpd 2.4.4 M :  mysql-5.5.28  P : php-5.4. ...

  8. 第五章 标准I/O

    5.1 引言 本章说明标准 I/O 库.因为不仅在 UNIX 上,而且在很多操作系统上都实现了此库,所以它由 ISO C 标准说明. 标准 I/O 库处理很多细节,例如缓冲区分配,以优化长度执行 I/ ...

  9. MySQL触发器和更新操作

    一.触发器概念 触发器(trigger):监视某种情况,并触发某种操作,它是提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动 ...

  10. 4 CSS的20/80个知识点

    1.css的基本构成 样式选择器 id选择器 元素选择器 2.css的盒模型 border padding margin 3.Atom快捷键 4.程序 (1)初始程序 <!DOCTYPE htm ...