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

[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

3 2 1
1 2
2 3
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)\) 的了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 22
#define maxm 500
#define maxs 2097152
#define MOD 998244353
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define LL long long

int n, m, p, w[maxn], cnt[maxn], can[maxs], sbit[maxs], inv[maxs], f[maxn][maxs], g[maxn][maxs];
pii es[maxm];

int fa[maxn];
int findset(int x) { return x == fa[x] ? x : fa[x] = findset(fa[x]); }

int Pow(int a, int b) {
    int ans = 1, t = a;
    while(b) {
        if(b & 1) ans = (LL)ans * t % MOD;
        t = (LL)t * t % MOD; b >>= 1;
    }
    return ans;
}

void FWT_or(int *a, int len, int tp) {
    int n = 1 << len;
    rep(i, 1, len) for(int j = 0; j < n; j += 1 << i) rep(k, 0, (1 << i >> 1) - 1) {
        int la = a[j+k], ra = a[j+k+(1<<i>>1)];
        if(tp > 0) {
            a[j+k] = (la + ra) % MOD;
            a[j+k+(1<<i>>1)] = la;
        }
        else {
            a[j+k] = ra;
            a[j+k+(1<<i>>1)] = (la - ra + MOD) % MOD;
        }
    }
    return ;
}

int main() {
    n = read(); m = read(); p = read();
    rep(i, 1, m) {
        int a = read() - 1, b = read() - 1;
        es[i] = mp(a, b);
    }
    rep(i, 0, n - 1) w[i] = read();

    int all = (1 << n) - 1;
    rep(s, 1, all) {
        int c = 0, cbit;
        rep(i, 0, n - 1) if(s >> i & 1) sbit[s] += w[i], c++;
        cbit = c;
        inv[s] = Pow(sbit[s], MOD - 2);
        rep(i, 0, n - 1) fa[i] = i, cnt[i] = 0;
        rep(i, 1, m) if((s >> es[i].x & 1) && (s >> es[i].y & 1)) {
            int u = findset(es[i].x), v = findset(es[i].y);
            if(u != v) fa[v] = u, c--;
            cnt[es[i].x]++; cnt[es[i].y]++;
        }
        bool has = 0;
        rep(i, 0, n - 1) if(s >> i & 1) has |= cnt[i] & 1;
        if(has || c > 1) can[s] = 1, g[cbit][s] = Pow(sbit[s], p);
    }

    f[0][0] = 1;
    FWT_or(f[0], n, 1);

    rep(i, 0, n) FWT_or(g[i], n, 1);
    rep(i, 1, n) {
        rep(j, 1, i) rep(k, 0, all) (f[i][k] += (LL)g[j][k] * f[i-j][k] % MOD) %= MOD;
        FWT_or(f[i], n, -1);
        rep(k, 0, all) f[i][k] = (LL)f[i][k] * Pow(inv[k], p) % MOD;
        if(i < n) FWT_or(f[i], n, 1);
    }

    printf("%d\n", f[n][all]);

    return 0;
}

原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8450096.html

时间: 2024-08-30 06:43:26

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

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

合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方案的满意度之和,枚举子集转移,则有f[S]=Σg[S']*f[S^S']*(sum[S']/sum[S])p (S'?S),其中g[S]为S集合是否合法,sum[S]为S集合人口数之和.复杂度O(3n).这个式子非常显然,就这么送了50分.p这么小显得非常奇怪但也没有任何卵用. 考虑优化.转移方程写

bzoj5153 [Wc2018]州区划分

题目链接 正解:子集和变换. 考场上只会暴力和$p=0$的情况,还只会$O(2^{n}*n^{3})$的. 然而这题题面出锅,导致考场上一直在卡裸暴力,后面的部分分没写了..听$laofu$说$O(2^{n}*n^{3})$可以过.. 所以直接讲正解.. 我们假设每个城市可以在两个不同集合,那么可以把子集卷积变成或卷积. 我们只要记下当前总共有多少个点,于是考虑设$f[i][S]$表示$i$个点,集合为$S$的方案数. 最后的$f[n][all]$就是答案,显然这个状态中的每个城市只会出现一次.

WC2018 州区划分

题目描述: luogu 题解: 设$f[S]$表示选集合$S$时所有满意度乘积之和,$W[S]$表示集合$S$中选中的$w$之和.显然有这样一个式子:$$f[S]= \frac{1}{W[S]^p} \sum\limits_{T \subseteq S}f[T]*W[S-T]^p*[check(S-T)]$$ 后面$check$的意思是判断$S-T$是否合法. 原题义中不合法的条件是存在一条欧拉回路.那么: 若图不连通则不存在. 若一个点的度数是奇数则不存在 单个点一定存在 这样可以$O(2^n

UOJ#348. 【WC2018】州区划分

原文链接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]$$ 这东西是

UOJ348. 【WC2018】州区划分

UOJ348. [WC2018]州区划分 http://uoj.ac/problem/348 分析: 设\(g(S)=(\sum\limits_{x\in S}w_x)^p[合法]\) \(f(S)\)表示\(S\)集合内的答案. \(f(S)=\sum\limits_{T\subseteq S,|T|>0}g(T)f(S-T)s(S)\). 这玩意可以使用占位多项式搞搞. 大概就是形如\(f(S)=\sum\limits_{P|Q=S,|P|+|Q|=S}g(P)h(Q)\). 多开一维表示\

UOJ#348 州区划分

解:有一个很显然的状压...... 就设f[s]表示选的点集为s的时候所有方案的权值和. 于是有f[s] = f[s \ t] * (sum[t] / sum[s])P. 这枚举子集是3n的. 然后发现这是子集卷积,参考资料. 于是就FWT搞一下...看代码 1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 30, M = 2100000, MO = 998244353; 5 6 struct Edge {

uoj348【WC2018】州区划分

题目链接 直接讲吨吨吨给的标准做法吧.记\(f(i,j)\)表示各个州(可以重叠)的城市数量之和为i,这些州的并集为j的方案数,反正若有两个州之间有交集最后的\(|j|\)会不等于\(i\).有 \(f(i,s)=\sum_{s1} \sum_{s2}[s1|s2==s] \ f(i-|s2|,s1)*can(s2) (\frac{vals(s2)}{vals(s)})^p\) \(f(i,s)*vals(s)^p=\sum_j \sum_{|s2|=j} \sum_{s1} [s1|s2==s

uoj#349 【WC2018】即时战略

题目链接 正解:$link-cut \ tree$. 这道题我在考场上从看题到放弃只花了$20$多分钟.. 爆刚$t2$无果,$12$点的钟声响起,我无奈地开始看这道题,然后发现了生的希望.. 只写了二十几分钟,然后又滚回去刚$t2$了..正解根本就没去想了(虽然本来也不会.. 不得不说这道题的标算还是很妙的,我就算去想也不可能往$LCT$这方面想.. 我们每次新开一个点,就直接从根结点开始$explore$. 我们可以用$LCT$维护当前这棵树的链,于是每次从现在$splay$的根结点开始往下

UVA 348 矩阵链乘

UVA 348 题意: 给出 N 个矩阵(A1,A2,...,An),求完全括号化方案,使得计算乘积(A1A2...An)所需乘法次数最少.并输出方案. 解题: 算法导论是个好东西   讲的很详细~ 假设矩阵 A 和 B 相乘,那 A 的列数必须要和 B 的行数相同,即 若 A 的行列数为(x,y),则 B 须为(y,z), 它们相乘得到一个(x,z)的矩阵:需要乘 xyz 次.题目把相乘的顺序给出了,我们做的就是添加括号了.把所有矩阵用一个序列 P 表示,第 i 个矩阵的行列数为 P(i-1)