重庆八中集训 day4

20220617

sign

题意

一个 \(1\) 为根的树,每个点有点权 \(a_i\),然后一个方案的时候,你就可以选择子树里节点 \(j\) 的点权 \(b_j \in [0, a_i]\),然后子树 \(u\) 的权值就是 \(son_u^{\sum_{i} bi}\),其中 \(son_u\) 表示 \(u\) 的儿子数。然后求对于每个子树来说,所有方案的权值之和。

题解

我们考虑,不同的 \(son_k\) 最多有 \(O(\sqrt N)\) 个。然后就是你对于一个子树 \(i\),然后记 \(f_{i, j}\) 表示当前 \(son_u = j\) 的权值之和。然后一个节点的贡献明显就是 \(\sum_{i\ge 0} son_u ^ i\) 这个可以等比数列求和快速算。

注意到快速幂的 \(\log A\) 不能要,怎么办捏,我们注意到可令 \(B = \sqrt {A}\),然后对于小于 \(B\) 的幂次预处理,然后大于 \(B\) 的幂次,对于原先的 \(son_u\),我们变成 \(son_u ^ B\) 之后,在预处理 \(B\) 个就可以 \(O(1)\) 查询快速幂。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1e5 + 10, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
const int MAXM = 10005;
int N, d[MAXN], fa[MAXN], t[MAXN], A[MAXN], f[MAXN][500], ans[MAXN], pw1[500][MAXM], pw2[500][MAXM], INV[MAXN];
Graph<MAXN, MAXN> tr;
inline int qpow(int x, int y) {return (ll) pw2[x][y / MAXM] * pw1[x][y % MAXM] % MOD;}
inline int gets(int x, int y) {
	// 1 + t[x] + t[x] ^ 2 + ... + t[x] ^ y
	if (t[x] == 1) return y + 1;
	return (qpow(x, y + 1) - 1LL) * INV[x] % MOD;
}
void dfs(int u) {
	for (int i = 1; i <= *t; ++i) f[u][i] = gets(i, A[u]);
	go(tr, u) {
		dfs(v);
		for (int j = 1; j <= *t; ++j) f[u][j] = (ll) f[u][j] * f[v][j] % MOD;
	}
	ans[u] = d[u] ? f[u][std::lower_bound(t + 1, t + 1 + *t, d[u]) - t] : 1;
}
int main() {
	freopen("sign.in", "r", stdin);
	freopen("sign.out", "w", stdout);
	qwq::init(20050112);
	read(N);
	tr.init();
	for (int i = 2; i <= N; ++i) read(fa[i]), tr.add_edge(fa[i], i), d[fa[i]]++;
	for (int i = 1; i <= N; ++i) if (d[i]) t[++*t] = d[i];
	for (int i = 1; i <= N; ++i) read(A[i]);
	sort(t + 1, t + 1 + *t);
	*t = unique(t + 1, t + 1 + *t) - t - 1;
	for (int i = 1; i <= *t; ++i) {
		INV[i] = Ksm(t[i] - 1, MOD - 2);
		pw1[i][0] = pw2[i][0] = 1;
		for (int j = 1; j < MAXM; ++j) pw1[i][j] = (ll) pw1[i][j - 1] * t[i] % MOD;
		pw2[i][1] = (ll) pw1[i][MAXM - 1] * t[i] % MOD;
		for (int j = 2; j < MAXM; ++j) pw2[i][j] = (ll) pw2[i][j - 1] * pw2[i][1] % MOD;
	}
	dfs(1);
	for (int i = 1; i <= N; ++i) printf("%d\n", ans[i]);
	return (0-0);
}

match

题意

两个串 \(s,t\),然后执行下面这个算法,

match(s, t) {
	i = 1;
	cur = 0;
	while (i <= N) {
		if (cur < M and s[i] = t[cur + 1]) ++cur;
		else cur = 0;
		f[i] = cur;
	}
}

然后捏,你本来想要得到的 \(f_i\),是最大的 \(l\) 使得 \(s[i - l + 1:i] = t[1:l]\)

问现在给你一个 \(s\),然后问,有多少 \(t\) 满足上面那个算法是正确的。

题解

首先一个 \(t\) 什么时候是合法的,你首先要找一个最长匹配,肯定是用 \(kmp\) 啊,然后,每次 \(kmp\) 失配的时候都要跳到 \(0\),很神奇。

我们枚举 \(s\) 中的一个子串他是最长的能和 \(T\) 的前缀匹配的节点,匹配长度为 \(l\)。之后,我们对于这段前缀之后的部分,显然可以随便填,然后方案数是 \(5 ^ {m - l - 1}\),然后需要注意的是,\(l+1\) 这个位置的字符应该不能和 \(S\) 更多的匹配,所以要 ban 掉字母,为了不能更长的匹配。

然后做完了,时间复杂度为 \(O(N ^ 3)\)。然后过了。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 2005, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
int N, M, ans, ch[MAXN][5], fail[MAXN], ncnt = 1, tr[MAXN * MAXN][5], pw[MAXN];
char s[MAXN];
void chk(int d) {
	bool ban[5];
	memset(ban, 0, sizeof ban);
	int u = 0;
	for (int i = 1; i <= N; ++i) {
		if (ch[u][s[i] - 'a'] && ch[u][s[i] - 'a'] != u + 1) return;
		if (u == d) ban[s[i] - 'a'] = 1;
		u = ch[u][s[i] - 'a'];
	}
	int cnt = 0;
	for (int i = 0; i < 5; ++i) cnt += !ban[i];
	if (d == M) ans = Mod(ans + 1);
	else ans = (ans + (ll) cnt * pw[M - d - 1]) % MOD;
}
void dfs(int u, int dep, int s) {
	if (~s) {
		for (int i = 0; i < 5; ++i) ch[dep - 1][i] = ch[fail[dep - 1]][i];
		fail[dep] = ch[dep - 1][s];
		ch[dep - 1][s] = dep;
		for (int i = 0; i < 5; ++i) ch[dep][i] = ch[fail[dep]][i];
	}
	chk(dep);
	if (dep < M) for (int i = 0; i < 5; ++i) if (tr[u][i]) dfs(tr[u][i], dep + 1, i);
}
int main() {
	freopen("match.in", "r", stdin);
	freopen("match.out", "w", stdout);
	pw[0] = 1;
	for (int i = 1; i < MAXN; ++i) pw[i] = pw[i - 1] * 5LL % MOD;
	qwq::init(20050112);
	read(N, M);
	reads(s + 1);
	for (int i = 1; i <= N; ++i) {
		int nw = 1;
		for (int j = i; j <= N; ++j) {
			if (!tr[nw][s[j] - 'a']) tr[nw][s[j] - 'a'] = ++ncnt;
			nw = tr[nw][s[j] - 'a'];
		}
	}
	fail[0] = MAXN - 1;
	dfs(1, 0, -1);
	ans = (ll) ans * Ksm(pw[M], MOD - 2) % MOD;
	printf("%d\n", ans);
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

tree

题意

给你一个 \(N\) 个节点,\(1\) 为根的有根树,然后每条边有边权。求 \(Q\) 次询问,每次询问 \(l,r\),求 \(l \le i \le j \le r\) 的所有点对,有多少个不同的 \(dep(lca(i, j))\)

题解

首先,考虑对于某个 \(dep\) 求出来它可以贡献的区间,比如说,对于一个点 \(x\),他下面两个点 \((y,z)\) 并且 \(y < z\),于是可以贡献给 \(([1, y], [z, N])\) 这个区间答案,然后一个询问就是 \(([l,r])\) 的单点查询。

发现一个子树里的 \(i\),只要有他的前缀,后缀贡献就好了。

考虑启发式合并即可,维护 set 可以将矩形个数减少为 \(N\log N\),之后用 map<vector<int>> 存一下,然后考虑求一个颜色矩阵的并,我们知道这些矩阵全是 2-side 的,于是只要按照 \((x, y)\) 排序,首先对于一个 \(x\) 保留最小的 \(y\),然后再维护一个单调队列即可。

这就是矩形了。之后就是矩形加法,单点查询,然后离线,扫描线,树状数组。

so easy。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1e5 + 10, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac, w;} e[M_num];
	inline void add_edge(int x, int y, int w) {e[*H] = {y, H[x], w};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
int N, M, ans[MAXN * 5];
ll d[MAXN], t[MAXN];
vector<array<int, 2U>> Orz_jzm[MAXN], opt[MAXN], q[MAXN];
Graph<MAXN, MAXN * 2> tr;
set<int> nd[MAXN];
using std::lower_bound;
void dfs(int u, int lst) {go(tr, u) if (v != lst) d[v] = d[u] + tr.e[i].w, dfs(v, u);}
void dfs2(int u, int lst) {
	Orz_jzm[d[u]].push_back({u, u});
	nd[u].insert(u);
	go(tr, u) if (v != lst) {
		dfs2(v, u);
		if (nd[v].size() > nd[u].size()) nd[u].swap(nd[v]);
		for (auto &i: nd[v]) {
			auto it = nd[u].lower_bound(i);
			if (it != nd[u].end()) Orz_jzm[d[u]].push_back({i, *it});
			if (it != nd[u].begin()) Orz_jzm[d[u]].push_back({*std::prev(it), i});
		}
		for (auto &i: nd[v]) nd[u].insert(i);
	}
}
struct Fenwick_Tree {
	int lim, sc[MAXN];
	inline void set(int _N) {lim  = _N;}
	inline void add(int x, int y) {for (; x <= lim; x += x & -x) sc[x] += y;}
	inline int qry(int x) {int r = 0; for (; x; x -= x & -x) r += sc[x]; return r;}
} c9;
inline void upd(int x, int y, int z) {opt[z].push_back({x, 1}), opt[z].push_back({y + 1, -1});}
int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	read(N, M);
	tr.init();
	for (int i = 1, x, y, w; i < N; ++i) read(x, y, w), tr.add_edge(x, y, w), tr.add_edge(y, x, w);
	dfs(1, 0);
	for (int i = 1; i <= N; ++i) t[i] = d[i];
	sort(t + 1, t + 1 + N);
	*t = unique(t + 1, t + 1 + N) - t - 1;
	for (int i = 1; i <= N; ++i) d[i] = lower_bound(t + 1, t + 1 + *t, d[i]) - t;//, O(d[i]);
	dfs2(1, 0);
	for (int i = 1; i <= *t; ++i) {
		sort(Orz_jzm[i].begin(), Orz_jzm[i].end());
		int lstx = -1;
		vector<array<int, 2U>> jzm_ak;
		for (auto &j: Orz_jzm[i]) if (j[0] != lstx) lstx = j[0], jzm_ak.push_back(j);
		vector<array<int, 2U>> sorry_to_xyx;
		for (auto &j: jzm_ak) {
			while (sorry_to_xyx.size() && sorry_to_xyx.back()[1] >= j[1]) sorry_to_xyx.pop_back();
			sorry_to_xyx.push_back(j);
		}
		int lst = 0;
		for (auto &j: sorry_to_xyx) upd(lst + 1, j[0], j[1]), lst = j[0];
	}
	for (int i = 1, l, r; i <= M; ++i) read(l, r), q[r].push_back({l, i});
	c9.set(N);
	for (int i = 1; i <= N; ++i) {
		for (auto &j: opt[i]) c9.add(j[0], j[1]);
		for (auto &j: q[i]) ans[j[1]] = c9.qry(j[0]);
	}
	for (int i = 1; i <= M; ++i) printf("%d\n", ans[i]);
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

丁真追妹子

顶针哥哥有 \(N\) 个妹子,第 \(i\) 个妹子可以接受在连续 \(b_i\) 天和丁真哥哥聊天,否则她会把理塘会0000拉黑。

丁真哥哥要在接下来的 \(M\) 天,每天找 \(k_i\) 个妹子聊天,他想被最少的妹子拉黑。

请你给出丁真哥哥最后最多还剩下多少个妹子没有拉黑他。

  • \(b\) 固定 \(k\) 不固定 判定是否保存所有妹子
  • \(k\) 固定 \(b\) 不固定 判定是否保存所有妹子
posted @ 2022-06-18 09:29  siriehn_nx  阅读(55)  评论(0编辑  收藏  举报