洛谷 P4365 [九省联考2018]秘密袭击coat(融合题)
洛谷 P4365 [九省联考2018]秘密袭击coat(融合题)
题目大意
开局一棵树,点有点权,求对于所有树上的联通块 T,求所有 T 中第 k 大点权的和。所有的点权 \(\in [1,W]\)
数据范围
\[1 \le k \le n \le 1666\\
1 \le W \le 1666
\]
解题思路
正解跑不过暴力.jpg 😭
先套路的进行转化,那么这题将被解决一小半(对暴力来说甚至事全部)
\[\sum_{T \subseteq S}K_{th} \ of \ T\\
\sum_{i=1}^Wi \times \sum_{T \subseteq S} [K_{th} \ of \ T = i]\\
\sum_{i=1}^{W}\sum_{T \subseteq S} [K_{th} \ of \ T \ge i]\\
\sum_{i=1}^{W}\sum_{T \subseteq S} [cnt[i]\le k]\\
\]
所以我们计算连通块根节点事 \(x\) 的答案并求和即可。设 \(dp[x][i][j]\) 表示当前以 x 为根节点的联通块里,权值大于 i 的点的个数等于 j 的方案数,有
\[Ans = \sum_{x=1}^n\sum_{i=1}^W\sum_{j=k}^nf[x][i][j]
\]
另设 \(g[i][j] = \sum_{x=1}^nf[x][i][j]\) ,有 \(Ans = \sum_{i=1}^W\sum_{j=k}^ng[i][j]\)。
来看 \(f\) 的暴力转移
\[f[x][i][j] = \prod f[y][i][t] \ \ \ \ \ \ \ (\sum t = j - [val[x] \ge i])
\]
不难发现它是一个背包,如果把 \(f[x][i]\) 看做生成函数呢,有
\[F[x][i] = x^{[val[x] \ge i]} \prod (F[y][i] + 1)
\]
如果 \(\Theta(n^2)\) 化成点值,转移时直接做点值乘法,最后我们直接再 \(\Theta(n^2)\) 插值回去即可,当然我们插回去用的事最后的 G 而不是 F,否则复杂度大失败。注意 F 和 G 的次数都事 n。
所以我们枚举当前带入 \(x_i = i\),求出最后的点值。
另外显然可以发现 i 这一维事大大不满的,也就是说有很多位置的值都是相同的。所以我们采用线段树合并即可。
容易发现要维护这几个操作
- 整体设为 1
- 整体加 1
- 对应位相乘
- 前缀乘一个数
这几个都可以用线段树合并来维护
- 整体设为 1 (打区间覆盖标记)
- 整体加 1 (打区间加标记)
- 对应位相乘 (线段树合并+乘法标记)
- 前缀乘一个数 (乘法标记)
要注意的细节事,线段树合并时暴力新建儿子并下传标记,看两个节点是否可以合并直接看是否有一个打了区间覆盖标记即可,标记的顺序问题不用再说了。
最后再插值回来即可。
先贴个暴力程序
/*
/> フ
| _ _|
/`ミ _x 彡
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
*/
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=x*10+(c^48);
if (f) x=-x;
}
template<typename F>
inline void write(F x, char ed = '\n') {
static short st[30];short tp=0;
if(x<0) putchar('-'),x=-x;
do st[++tp]=x%10,x/=10; while(x);
while(tp) putchar('0'|st[tp--]);
putchar(ed);
}
template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }
template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }
const unsigned int P = 64123;
const int N = 2058;
namespace Lagrange {
#define uint unsigned int
int siz, n, k;
uint Inv(uint x, uint mi = P - 2) {
uint res = 1;
for (; mi; mi >>= 1, x = x * x % P)
if (mi & 1) res = res * x % P;
return res;
}
uint y[N];
struct Poly {
unsigned int f[N];
Poly () { memset(f, 0, siz); }
uint & operator [] (int i) { return f[i]; }
Poly operator + (Poly t) {
Poly res;
for (int i = 0;i <= n; i++) res[i] = (f[i] + t[i]) % P;
return res;
}
void operator *= (uint b) { for (int i = 0;i <= n; i++) f[i] = f[i] * b % P; }
Poly operator * (uint b) {
Poly t;
for (int i = n;i > 0; i--) t[i] = (f[i-1] + (P - f[i]) * b) % P;
return t[0] = (P - f[0]) * b % P, t;
}
Poly operator / (uint b) {
Poly res = *this, t;
for (int i = n;i >= 1; i--)
t[i-1] = res[i], res[i-1] = (res[i-1] + res[i] * b) % P;
return t;
}
}F[N];
int main(int nn) {
n = nn, siz = n * 8 + 32;
F[0][0] = 1;
for (int i = 1;i <= n; i++) F[0] = F[0] * i;
for (int i = 1;i <= n; i++) F[i] = F[0] / i;
for (int i = 1;i <= n; i++) {
uint mul = 1;
for (int j = 1;j <= n; j++)
if (i != j) mul = mul * (P + i - j) % P;
mul = y[i] * Inv(mul) % P;
F[i] *= mul;
if (i != 1) F[i] = F[i-1] + F[i];
}
return 0;
}
}
uint f[N][N], d[N], res;
int h[N], ne[N<<1], to[N<<1], tot, n, w, k;
inline void add(int x, int y) {
ne[++tot] = h[x], to[h[x] = tot] = y;
}
void dfs(int x, int fa, int ml) {
for (int i = 1;i <= w; i++) f[x][i] = 1;
for (int i = h[x]; i; i = ne[i]) {
int y = to[i]; if (y == fa) continue;
dfs(y, x, ml);
for (int j = 1; j <= w; j++)
f[x][j] = f[x][j] * (f[y][j] + 1) % P;
}
for (int j = 1;j <= d[x]; j++)
f[x][j] = f[x][j] * ml % P;
for (int j = 1;j <= w; j++) res = (res + f[x][j]) % P;
}
int main() {
read(n), read(k), read(w);
for (int i = 1;i <= n; i++) read(d[i]);
for (int i = 1, x, y;i < n; i++)
read(x), read(y), add(x, y), add(y, x);
for (int i = 1;i <= n + 1; i++)
dfs(1, 0, i), Lagrange::y[i] = res, res = 0;
Lagrange::main(n + 1); uint ans = 0;
for (int i = k;i <= n; i++)
ans = (ans + Lagrange::F[n+1][i]) % P;
write(ans);
return 0;
}
这是加上整体 dp 的版本
/*
/> フ
| _ _|
/`ミ _x 彡
/ |
/ ヽ ?
/ ̄| | | |
| ( ̄ヽ__ヽ_)_)
\二つ
*/
%:pragma GCC optimize(2)
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=x*10+(c^48);
if (f) x=-x;
}
template<typename F>
inline void write(F x, char ed = '\n') {
static short st[30];short tp=0;
if(x<0) putchar('-'),x=-x;
do st[++tp]=x%10,x/=10; while(x);
while(tp) putchar('0'|st[tp--]);
putchar(ed);
}
template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }
template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }
const unsigned int P = 64123;
const int N = 2058;
#define uint unsigned int
namespace Lagrange {
int siz, n, k;
uint Inv(uint x, uint mi = P - 2) {
uint res = 1;
for (; mi; mi >>= 1, x = x * x % P)
if (mi & 1) res = res * x % P;
return res;
}
uint y[N];
struct Poly {
unsigned int f[N];
Poly () { memset(f, 0, siz); }
uint & operator [] (int i) { return f[i]; }
Poly operator + (Poly t) {
Poly res;
for (int i = 0;i <= n; i++) res[i] = (f[i] + t[i]) % P;
return res;
}
void operator *= (uint b) { for (int i = 0;i <= n; i++) f[i] = f[i] * b % P; }
Poly operator * (uint b) {
Poly t;
for (int i = n;i > 0; i--)
t[i] = (f[i-1] + (P - f[i]) * b) % P;
return t[0] = (P - f[0]) * b % P, t;
}
Poly operator / (uint b) {
Poly res = *this, t;
for (int i = n;i >= 1; i--)
t[i-1] = res[i], res[i-1] = (res[i-1] + res[i] * b) % P;
return t;
}
}F[N];
int main(int nn) {
n = nn, siz = n * 4 + 32;
F[0][0] = 1;
for (int i = 1;i <= n; i++) F[0] = F[0] * i;
for (int i = 1;i <= n; i++) F[i] = F[0] / i;
for (int i = 1;i <= n; i++) {
uint mul = 1;
for (int j = 1;j <= n; j++)
if (i != j) mul = mul * (P + i - j) % P;
mul = y[i] * Inv(mul) % P;
F[i] *= mul;
if (i != 1) F[i] = F[i-1] + F[i];
}
return 0;
}
}
uint f[N][N], d[N], res;
int h[N], ne[N<<1], to[N<<1], tot, n, w, k, cnt;
inline void adde(int x, int y) {
ne[++tot] = h[x], to[h[x] = tot] = y;
}
struct node {
uint sum, tag, mul, add;
int ls, rs;
#define add(p) t[p].add
#define ls(p) t[p].ls
#define rs(p) t[p].rs
#define sum(p) t[p].sum
#define tag(p) t[p].tag
#define mul(p) t[p].mul
}t[300050];
int rt[N];
inline int nd(void) {
++cnt, mul(cnt) = 1, tag(cnt) = sum(cnt) = add(cnt) = 0;
return ls(cnt) = rs(cnt) = 0, cnt;
}
inline void Tag(int p, uint T, int l, int r) {
tag(p) = T, sum(p) = T * (r - l + 1) % P, mul(p) = 1, add(p) = 0;
}
inline void Mul(int p, uint T) {
tag(p) = tag(p) * T % P, sum(p) = sum(p) * T % P;
if (!tag(p)) mul(p) = mul(p) * T % P, add(p) = add(p) * T % P;
}
inline void Add(int p, uint T, int l, int r) {
if (tag(p)) { sum(p) = (sum(p) + (r - l + 1) * T) % P, tag(p) = (tag(p) + T) % P; return; }
add(p) = (add(p) + T) % P, sum(p) = (sum(p) + T * (r - l + 1)) % P;
}
inline void spread(int p, int l, int r, int mid) {
if (!ls(p)) ls(p) = nd();
if (!rs(p)) rs(p) = nd();
if (tag(p)) Tag(ls(p), tag(p), l, mid), Tag(rs(p), tag(p), mid + 1, r), tag(p) = 0;
if (mul(p) != 1) Mul(ls(p), mul(p)), Mul(rs(p), mul(p)), mul(p) = 1;
if (add(p)) Add(ls(p), add(p), l, mid), Add(rs(p), add(p), mid + 1, r), add(p) = 0;
}
void mulchange(int p, int l, int r, int R, uint ml) {
if (r <= R) return Mul(p, ml);
int mid = (l + r) >> 1; spread(p, l, r, mid);
mulchange(ls(p), l, mid, R, ml);
if (mid < R) mulchange(rs(p), mid + 1, r, R, ml);
sum(p) = (sum(ls(p)) + sum(rs(p))) % P;
}
void Merge(int &x, int y, int l, int r) {
if (l == r) return sum(x) = sum(x) * sum(y) % P, void();
if (tag(y)) return Mul(x, tag(y));
if (tag(x)) return swap(x, y), Mul(x, tag(y));
int mid = (l + r) >> 1;
spread(x, l, r, mid), spread(y, l, r, mid);
Merge(ls(x), ls(y), l, mid);
Merge(rs(x), rs(y), mid + 1, r);
sum(x) = (sum(ls(x)) + sum(rs(x))) % P;
}
void dfs(int x, int fa, uint ml) {
Tag(rt[x] = nd(), 1, 1, w);
for (int i = h[x]; i; i = ne[i]) {
int y = to[i]; if (y == fa) continue;
dfs(y, x, ml), Add(rt[y], 1, 1, w);
Merge(rt[x], rt[y], 1, w);
}
mulchange(rt[x], 1, w, d[x], ml);
res = (sum(rt[x]) + res) % P;
}
int main() {
read(n), read(k), read(w);
for (int i = 1;i <= n; i++) read(d[i]);
for (int i = 1, x, y;i < n; i++)
read(x), read(y), adde(x, y), adde(y, x);
for (int i = 1;i <= n + 1; i++)
cnt = 0, dfs(1, 0, i), Lagrange::y[i] = res, res = 0;
Lagrange::main(n + 1); uint ans = 0;
for (int i = k;i <= n; i++)
ans = (ans + Lagrange::F[n+1][i]) % P;
write(ans);
return 0;
}