洛谷 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;
}
posted @ 2020-09-06 19:23  Hs-black  阅读(189)  评论(0编辑  收藏  举报