专栏文章

题解:P8290 [省选联考 2022] 填树

P8290题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipksqw3
此快照首次捕获于
2025/12/03 13:38
3 个月前
此快照最后确认于
2025/12/03 13:38
3 个月前
查看原文

[省选联考 2022] 填树

如果不知道拉格朗日插值,其实很难有勇气做下去。因此,本篇题解认为读者已经熟悉拉格朗日插值,并从此角度去考虑问题。
首先,想着复杂度关于 nn 的动态规划手足无措时,就会发现这个问题非常依赖值域。说到值域,应当脑中一闪而过拉格朗日插值的想法,在这个方面想下去。
接着会想到枚举一下最小值,就知道了最大值,范围确定下来,是容易 O(n)O(n) 动态规划求方案数及和的。不过不久会注意到一个问题,举个例子,[l,r][l, r][l+1,r+1][l+1, r+1] 两个范围的贡献中,值的范围在 [l+1,r][l+1, r] 中的贡献重复计算两次。不过这个是好处理的,分别计算 [l,r][l, r][l+1,r][l+1, r] 的贡献,从前者中减去后者,就变成了值在 [l,r][l, r],且最小值恰好取到 ll,不重不漏。代码参考
做了以上的工作,复杂度就是 O(nV)O(nV) 的了,然后对于一步步枚举最小值计算贡献的操作,就拿拉格朗日插值去优化他。回顾动态规划的过程,当范围连续变化的时候,一个点的单独的方案数是一次函数和常数线段拼起来的,和则是二次函数和常数线段拼起来。这时去找从函数到常数线段的分界点,发现是在当目前枚举到的范围和点的权值范围的边界刚好相交时。因此只需要在这些位置分个段,然后连续的区间做拉格朗日插值就可以了。由于段的个数是 O(n)O(n) 的,而单次拉格朗日插值也是 O(n)O(n) 的,所以总复杂度 O(n3)O(n^3)
Code
CPP
#include <iostream>
#include <algorithm>
#include <string.h>
#include <iomanip>
#include <bitset>
#include <math.h>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#define fst first
#define scd second
#define db double
#define ll long long
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector <int>
#define pii pair <int, int>
#define sz(x) ((int)x.size())
#define ms(f, x) memset(f, x, sizeof(f))
#define L(i, j, k) for (int i=(j); i<=(k); ++i)
#define R(i, j, k) for (int i=(j); i>=(k); --i)
#define ACN(i, H_u) for (int i=H_u; i; i=E[i].nxt)
using namespace std;
template <typename INT> void rd(INT &res) {
	res=0; bool f=false; char ch=getchar();
	while (ch<'0'||ch>'9') f|=ch=='-', ch=getchar();
	while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48), ch=getchar();
	res=(f?-res:res);
}
template <typename INT, typename...Args>
void rd(INT &x, Args &...y) { rd(x), rd(y...); }
//dfs
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=200;
const int N=maxn+10;
int H[N], edge_cnt, n, m, kn, sum[N], cnt[N], lb, rb, fac[N], inv[N], pre[N], suf[N], d[N<<2], t1[N], t2[N], res1, res2;
//wmr
int moda(int x) { return x>=mod?x-mod:x; }
int mods(int x) { return x<0?x+mod:x; }
struct Edge { int nxt, to; } E[N<<1];
void add(int u, int v) { E[++edge_cnt]={H[u], v}; H[u]=edge_cnt; }
struct node { int l, r; } a[N];
int quick_power(int x, int y) {
	int res=1;
	while (y) {
		if (y&1) res=(ll)res*x%mod;
		x=(ll)x*x%mod, y>>=1;
	}
	return res;
}
//incra
void dfs(int u, int pre) {
	int r=min(rb, a[u].r), l=max(lb, a[u].l);
	if (l>r) l=1, r=0;
	int c0=r-l+1, s0=((ll)(l+r)*(r-l+1)>>1)%mod;
	cnt[u]=c0, sum[u]=s0; res1=moda(res1+c0), res2=moda(res2+s0);
	ACN(i, H[u]) {
		int v=E[i].to;
		if (v==pre) continue;
		dfs(v, u);
		res1=(res1+(ll)cnt[u]*cnt[v])%mod, res2=(res2+(ll)cnt[u]*sum[v]+(ll)cnt[v]*sum[u])%mod;
		cnt[u]=(cnt[u]+(ll)c0*cnt[v])%mod, sum[u]=(sum[u]+(ll)cnt[v]*s0+(ll)c0*sum[v])%mod;
	}
}
int lag(int a[], int m) {
	int ans=0;
	pre[0]=1; L(i, 1, n+2) pre[i]=(ll)pre[i-1]*(m-i)%mod;
	suf[n+3]=1; R(i, n+2, 1) suf[i]=(ll)suf[i+1]*(m-i)%mod;
	L(i, 1, n+2) ans=((ll)a[i]*pre[i-1]%mod*suf[i+1]%mod*inv[i-1]%mod*inv[n+2-i]%mod*(((n+2-i)&1)?mod-1:1)+ans)%mod;
	return ans;
}
//lottle
signed main() {
//	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	fac[0]=1; L(i, 1, maxn+2) fac[i]=(ll)fac[i-1]*i%mod;
	inv[maxn+2]=quick_power(fac[maxn+2], mod-2); R(i, maxn+1, 0) inv[i]=(ll)inv[i+1]*(i+1)%mod;
	rd(n, kn);
	L(i, 1, n) {
		rd(a[i].l, a[i].r);
		d[i*4-3]=a[i].l, d[i*4-2]=max(a[i].l-kn, 0);
		d[i*4-1]=a[i].r, d[i*4]=max(a[i].r-kn, 0);
		d[n*4+1]=max(d[n*4+1], a[i].r+1);
	}
	sort(d+1, d+n*4+2); m=unique(d+1, d+n*4+2)-d-1;
	L(i, 1, n-1) { int u, v; rd(u, v); add(u, v), add(v, u); }
	int ans1=0, ans2=0;
	L(i, 1, m-1) {
		int rc=d[i+1]-d[i], cnt=min(n+2, rc);
		L(j, 1, cnt) {
			lb=d[i]+j, rb=d[i]+j+kn-1; res1=res2=0;
			dfs(1, 0);
			res1=mods(-res1), res2=mods(-res2);
			--lb; dfs(1, 0);
			ans1=moda(ans1+res1), ans2=moda(ans2+res2);
			t1[j]=ans1, t2[j]=ans2;
		}
		if (rc<=n+2) continue;
		ans1=lag(t1, rc), ans2=lag(t2, rc);
	}
	printf("%d\n%d\n", ans1, ans2);
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...