2021-11-09 集训补题

再次膜拜 ljs 神,又无线接近于AK!!!!ORZ!!!!

T1

Description

有 \(n\) 个元素为 \((w_i,t_i)\),有 \(Q\) 此查询,每次给出 \(x_i\),求选出 \(x_i\) 个元素使得所有元素的 \(\sum t\le T\) 且 \(w\) 中位数最大。

Solution

我 \(\Theta(n\log^2n)\) 保龄了。/kk

实际上你发现对于一个点可以二分出最大长度,做个后缀最大值就好了。不过要写主席树上二分。

T2

Description

给一个 \(n\) 个点 \(m\) 条有向边的图,每条边上有数字 \(0\) 或 \(1\),定义一个路径的长度为这个路径上依次经过的边上的数字拼在一起后在二进制下的值(前导 \(0\) 对该路径长度没有贡献)。现在需要你求出从 \(1\) 号点出发,到 \(2,3,...,n\) 号点的路径的长度的最小值。模 \(10^9+7\) 。

\(n\le 10^6\)

Solution

我写 \(\Theta(n\log n)\) 只有 \(80\) 分。/kk

可以先把从 \(1\) 号点能只⾛ \(0\) 边就能到达的点都缩成⼀个点。接下来我们要让路径经过的边数尽量少,在此前提下最⼩化字典序。可以考虑直接bfs,每次从队列前部取出所有距离相同的点并先遍历 \(0\) 边再遍历 \(1\) 边更新答案。我写的 01trie ,所以就成 \(\Theta(m\log n)\) 了。/kk

T3

Description

有 \(n\) 个随机变量 \(\in [1,A]\),求出和 \(\le m\) 的最大个数的期望。

\(n\le 100,1\le m,A\le 1000\)

Solution

我们考虑设 \(g_{i,j,s}\) 表示确定了 \(i\) 个数,最大值 \(\le j\),和 \(\le s\) 的方案数。那么:

\[\text{ans}\times A^n=\sum_{i=0}^{n} \sum_{j=1}^{A} \sum_{k=1}^{n-i} g_{i,j-1,m-k\times j}\times \binom{n}{i}\sum_{t\ge k}^{n-i} \binom{n-i}{t}\times (A-j)^{n-i-t} \]

这个实际上我们就是在枚举从小到大位置为 \(i+k\) 的值为 \(j\),比 \(j\) 小的有 \(i\) 个,\(j\) 有 \(t\) 个的贡献。

考虑如何计算 \(g_{i,j,s}\),你发现我们可以进行容斥,即:

\[g_{i,j,s}=\sum_{t=0} (-1)^t\binom{i}{t}\binom{s-t\times j}{i} \]

注意,我们是和 \(\le s\)。

T4

Description

给定两颗树 T1,T2,求 T1 有多少个连通块与 T2 同构。

\(|T1|\le 3000,|T2|\le 10\)

Solution

LYC Orz!!!!!!

我们可以直接树 hash + 树 dp来就好了,具体见代码。

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define mod 998244353
#define MAXN 1005

template <typename T> inline void read (T &x){x = 0;char c = getchar();int f = 1;while (!isdigit (c)) f *= (c == '-' ? -1 : 1),c = getchar();while (isdigit (c)) x = x * 10 + c - '0',c = getchar();x *= f;}
template <typename T> inline void write (T x){if (x < 0) putchar ('-'),x = -x;if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m;
vector <int> g[MAXN],h[MAXN];

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}

#define ull unsigned long long
#define seed 1000000007
#define pii pair<int,int>
#define se second
#define fi first
ull pw[MAXN];

int ans,siz[MAXN];
ull dfs (int u,int fa){
	siz[u] = 1;ull has = 1;
	for (Int v : h[u]) if (v ^ fa) has += dfs (v,u) * pw[siz[v]],siz[u] += siz[v];
	return has;
}

map <ull,int> mp,f[MAXN][55],tmp[55];
void dfs1 (int u,int fa){
	f[u][0][0] = f[u][1][1] = 1,siz[u] = 1;
	for (Int v : g[u]) if (v ^ fa){
		dfs1 (v,u);
		for (Int i = 1;i <= m;++ i) tmp[i].clear();
		for (Int su = 1;su <= min (siz[u],m);++ su)
			for (Int sv = 0;sv <= min (siz[v],m) && su + sv <= m;++ sv)
				for (auto it1 = f[u][su].begin();it1 != f[u][su].end();++ it1)
					for (auto it2 = f[v][sv].begin();it2 != f[v][sv].end();++ it2){
						ull has = (it1 -> fi) + (it2 -> fi) * pw[sv];
						Add (tmp[su + sv][has],mul (it1 -> se,it2 -> se));
					}
		for (Int i = 1;i <= m;++ i) f[u][i] = tmp[i];
		siz[u] += siz[v];
	}
	for (auto it = f[u][m].begin();it != f[u][m].end();++ it) if (mp[it -> fi]) Add (ans,it -> se);
}

signed main(){
	read (n);
	for (Int i = 2,u,v;i <= n;++ i) read (u),read (v),g[u].push_back (v),g[v].push_back (u);
	read (m);
	for (Int i = 2,u,v;i <= m;++ i) read (u),read (v),h[u].push_back (v),h[v].push_back (u);
	pw[0] = 1;for (Int i = 1;i <= max (n,m);++ i) pw[i] = pw[i - 1] * seed;
	for (Int i = 1;i <= m;++ i) mp[dfs (i,0)] = 1;dfs1 (1,0),write (ans),putchar ('\n');
	return 0;
}
上一篇:Removing Cards


下一篇:ABC221G Jumping sequence 题解