2025CSP-S模拟赛18 比赛总结

2025CSP-S模拟赛 18

前几天题改的不是很好,先空着。

然后就是今天学习了比较牛逼的快读快写。计划是以后写题把这种读写和 ios 都打上,以备不时之需。

另外一个就是以后比赛总结写得简洁一些,这只不过是一个复盘的过程,又不是写题解。

T1 flandre

可以证明,答案最优一定是取他的一段后缀。这个举几个例子就可以说明。

然后一次考虑每一个后缀,维护答案即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

int read() {
	int x = 0, f = 1; char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
int n, kk;
struct node {
	int a, id;
	bool operator < (const node & cmp) const {
		return a < cmp.a;
	}
} e[N];
unordered_map<int, int> len;
signed main() {
	n = read(), kk = read();
	for (int i = 1; i <= n; i++) {
		e[i].a = read();
		e[i].id = i;
	}
	sort(e + 1, e + 1 + n);
	int ans = -INF, id = 1;
	int now = 0;
	for (int i = n; i >= 1; i--) {
		now += e[i].a + kk * (n - i - len[e[i].a]);
		len[e[i].a]++;
		if (now > ans) {
			ans = now;
			id = i;
		}
	}
	printf("%lld %lld\n", ans, n - id + 1);
	for (int i = id; i <= n; i++) {
		printf("%lld ", e[i].id);
	}
	
	return 0;
}

T2 meirin

这题场上切了。

考虑拆贡献。考虑每个 \(b_i\) 对于答案的贡献:

\[\begin{array}{ll} ans & = & \sum_{l=1}^n\sum_{r=l}^n(\sum_{i=l}^ra_i)\times(\sum_{i=l}^rb_i) \\ & = & \sum_{i=1}^nb_i(\sum_{l=1}^i\sum_{r=i}^n\sum_{j=l}^ra_j)\\ & = & \sum_{i=1}^nb_i(\sum_{l=1}^i\sum_{r=i}^n(sa_r-sa_{l-1}))\\ & = & \sum_{i=1}^nb_i((\sum_{l=1}^i\sum_{r=i}^nsa_r)-(\sum_{l=1}^i\sum_{r=i}^nsa_{l-1}))\\ & = & \sum_{i=1}^nb_i((i\sum_{r=i}^nsa_r)-((n-i+1)\sum_{l=0}^{i-1}sa_l))\\ \end{array} \]

其中 \(sa_i\)\(a\) 的前缀和。

\(f_i\) 表示 \(b_i\) 后面这一坨,即 \(f_i=(i\sum_{r=i}^nsa_r)-((n-i+1)\sum_{l=0}^{i-1}sa_l)\)。如何求?给 \(sa\) 求个前缀和即可 \(O(n)\) 求出。则:

\[ans=\sum_{i=1}^nf_ib_i \]

每次修改给 \(l\)\(r\)\(b_i\) 加上 \(k\),则答案增加的值即为 \(k\sum_{i=l}^rf_i\)。对 \(f_i\) 求前缀和即可每次操作 \(O(1)\) 修改。

#include <bits/stdc++.h>
#define int long long

using namespace std;

namespace IO {
	const int bufsz = 1 << 20;
	char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
	char obuf[bufsz], *p3 = obuf, stk[50];
	#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
	#define flush() (fwrite(obuf, 1, p3 - obuf, stdout), p3 = obuf)
	#define putchar(ch) (p3 == obuf + bufsz && flush(), *p3++ = (ch))
	inline int read() {
		int x = 0; char ch = getchar(); bool t = 0;
		while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
		while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
		return t ? -x : x;
	}
	inline void write(int x, bool t = 1) {
		int top = 0;
		do {stk[++top] = x % 10 | 48; x /= 10;} while (x);
		while (top) putchar(stk[top--]);
		t ? putchar('\n') : putchar(' ');
	}
	struct FL {~FL() {flush();}} fl;
	#undef getchar()
	#undef putchar()
	#undef flush()
}
using IO::read;
using IO::write;
const int MOD = 1e9 + 7;
const int N = 5e5 + 10;
int n, qq, a[N], b[N];
int s[N], f[N], ss[N], sf[N];
signed main() {
	n = read(), qq = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= n; i++) b[i] = read();	
	for (int i = 1; i <= n; i++) {
		s[i] = (s[i - 1] + a[i]) % MOD;
		ss[i] = (ss[i - 1] + s[i]) % MOD;
	}
	for (int i = 1; i <= n; i++) {
		f[i] = ((ss[n] - ss[i - 1]) % MOD * i % MOD - ss[i - 1] * (n - i + 1) % MOD) % MOD;
		sf[i] = (sf[i - 1] + f[i]) % MOD;
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		ans = (ans + b[i] * f[i] % MOD) % MOD;
	}
	while (qq--) {
		int l = read(), r = read(), k = read();
		ans = (ans + (sf[r] - sf[l - 1]) % MOD * k % MOD) % MOD;
		write((ans + MOD) % MOD);
	}
	
	return 0;
}

T3 sakuya

考虑拆贡献。

考虑每条边对于答案的贡献。首先树形 dp 求出初始的贡献,即为 \(w_i\times num_i\)。其中 \(w\) 为边权,\(num\) 为这条边左右特殊点个数的乘积。然后当一条边的边权加上 \(k\),对答案增加的贡献即为 \(k\times num_i\)。对于每个点统计发出的所有边的 \(num\) 然后 \(O(1)\) 进行维护答案即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

namespace IO { 
// 这里的读写这么怪是因为当时数据锅了,快读过不了,只有 cin cout 能过,方便调试。不必在意。
	inline int read() {
		int x;
		cin >> x;
		return x;
	}
	inline void write(int x, bool t = 1) {
		cout << x << '\n';
	}
}
using IO::read;
using IO::write;
const int MOD = 998244353;
const int N = 5e5 + 10;
int n, m, qq, a[N];
struct edge {
	int y, w;
};
vector<edge> G[N];
int fpow(int a, int x) {
	a %= MOD;
	int ans = 1;
	while (x) {
		if (x & 1) ans = ans * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return ans;
}
int fact[N];
int fa[N];
int f[N], g[N], dp[N], ans;
void dfs(int x, int father) {
	fa[x] = father;
	for (edge i : G[x]) {
		int y = i.y;
		if (y == fa[x]) continue;
		dfs(y, x);
		f[x] += f[y];
		ans = (ans + g[y] * i.w % MOD) % MOD;
		dp[x] = (dp[x] + g[y]) % MOD;
	}
	g[x] = f[x] * (m - f[x]) % MOD * 2 % MOD * fact[m - 1] % MOD;
	dp[x] = (dp[x] + g[x]) % MOD;
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	n = read(), m = read();
	for (int i = 1; i < n; i++) {
		int x = read(), y = read(), z = read();
		G[x].push_back({y, z});
		G[y].push_back({x, z});
	}
	for (int i = 1; i <= m; i++) {
		a[i] = read();
		f[a[i]] = 1;
	}
	fact[0] = 1;
	for (int i = 1; i <= m; i++) fact[i] = fact[i - 1] * i % MOD;
	int ny = fpow(fact[m], MOD - 2);
	dfs(1, 0);
	ans = (ans + MOD) % MOD;
	qq = read();
	while (qq--) {
		int x = read(), k = read();
		ans = (ans + dp[x] * k % MOD) % MOD;
		write(ans * ny % MOD);
	}
	
	return 0;
}

T4 红楼 ~ Eastern Dream

一眼根号分治。

image

image

image

懒得写了,直接截图。

#include <bits/stdc++.h>
#define il inline
#define int long long

using namespace std;

namespace IO {
	const int bufsz = 1 << 20;
	char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
	char obuf[bufsz], *p3 = obuf, stk[50];
	#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
	#define flush() (fwrite(obuf, 1, p3 - obuf, stdout), p3 = obuf)
	#define putchar(ch) (p3 == obuf + bufsz && flush(), *p3++ = (ch))
	inline int read() {
		int x = 0; char ch = getchar(); bool t = 0;
		while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
		while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
		return t ? -x : x;
	}
	inline void write(int x, bool t = 1) {
		int top = 0;
		do {stk[++top] = x % 10 | 48; x /= 10;} while (x);
		while (top) putchar(stk[top--]);
		t ? putchar('\n') : putchar(' ');
	}
	struct FL {~FL() {flush();}} fl;
	#undef getchar()
	#undef putchar()
	#undef flush()
}
using IO::read;
using IO::write;
const int N = 2e5 + 10, M  = 500;
int n, m, a[N], sq;
int s[N];
int v[M][M], sv[M][M], c[N], ic[N];
int st[M], ed[M], beg[N], cc[N], icc[N];
il void init() {
	for (int i = 1; i <= sq; i++) {
		st[i] = n / sq * (i - 1) + 1;
		ed[i] = n / sq * i;
	}
	ed[sq] = n;
	for (int i = 1; i <= sq; i++) {
		for (int j = st[i]; j <= ed[i]; j++) {
			beg[j] = i;
		}
	}
}
il void update(int p, int x) {
	c[p] += x;
	cc[beg[p]] += x;
	ic[p] += x * p;
	icc[beg[p]] += x * p;
}
il int query(int l, int r) {
	if (l > r) return 0;
	if (beg[l] == beg[r]) {
		int res = 0;
		for (int i = l; i <= r; i++) res += c[i];
		return res;
	}
	int res = 0;
	for (int i = l; i <= ed[beg[l]]; i++) res += c[i];
	for (int i = st[beg[r]]; i <= r; i++) res += c[i];
	for (int i = beg[l] + 1; i < beg[r]; i++) {
		res += cc[i];
	}
	return res;
}
il int queryi(int l, int r) {
	if (l > r) return 0;
	if (beg[l] == beg[r]) {
		int res = 0;
		for (int i = l; i <= r; i++) res += ic[i];
		return res;
	}
	int res = 0;
	for (int i = l; i <= ed[beg[l]]; i++) res += ic[i];
	for (int i = st[beg[r]]; i <= r; i++) res += ic[i];
	for (int i = beg[l] + 1; i < beg[r]; i++) {
		res += icc[i];
	}
	return res;
}
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i];
	sq = sqrt(n);
	init();
	while (m--) {
		int op = read();
		if (op == 1) {
			int x = read(), y = read(), k = read();
			y = min(x - 1, y);
			if (x <= sq) {
				for (int i = 0; i <= y; i++) {
					v[x][i] += k;
				}
				sv[x][0] = v[x][0];
				for (int i = 1; i < x; i++) {
					sv[x][i] = sv[x][i - 1] + v[x][i];
				}
			} else {
				for (int i = 1; i <= n; i += x) {
					update(i, k);
					update(min(n + 1, i + y + 1), -k);
				}
			}
		} else {
			int l = read(), r = read();
			int ans = s[r] - s[l - 1];
			for (int i = 1; i <= sq; i++) {
				ans += sv[i][(r - 1) % i];
				ans -= sv[i][(l - 1) % i - 1];
				int ll = (l - 1) / i, rr = (r - 1) / i;
				ans += (rr - ll) * sv[i][i - 1];
			}
			ans += (r - l + 1) * query(1, l - 1) + (r + 1) * query(l, r) - queryi(l, r);
			printf("%lld\n", ans);
		}
	}
	
	return 0;
}
posted @ 2025-07-15 21:46  Zctf1088  阅读(25)  评论(0)    收藏  举报