2025/6/28 cw模拟赛总结

T1

密码的打表找规律题。

你发现只需要特判 \(n = 1,2,3\) 的情况,之后就是循环节,每 \(8\) 个一周期。

循环节第 \(3,4,7,8\) 个都是固定的分别是 \(6,4,2,0\)\(1,2\) 位上是 \(t = (\lfloor\frac{n - 1}{8}\rfloor \times 8 + 1) \times 2 + 8\)\(5,6\) 位上是 \(t + 12\)

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

using namespace std;

int n;

signed main() {
	scanf ("%lld", &n);
	if (n == 1 || n == 2) {
		printf ("2\n");
		return 0;
	}
	if (n == 3) {
		printf ("0\n");
		return 0;
	}
	
	n -= 3;
	int modNum = n % 8;
	int x = ((n - 1) / 8 * 8 + 1) * 2 + 8;
	
	if (modNum == 1) {
		printf ("%lld\n", x);
	}
	else if (modNum == 2) {
		printf ("%lld\n", x);
	}
	else if (modNum == 3) {
		printf ("6\n");
	}
	else if (modNum == 4) {
		printf ("4\n");
	}
	else if (modNum == 5) {
		printf ("%lld\n", x + 12);
	}
	else if (modNum == 6) {
		printf ("%lld\n", x + 12);
	}
	else if (modNum == 7) {
		printf ("2\n");
	}
	else if (modNum == 0) {
		printf ("0\n");
	}
	
	return 0;
}

T2

\(f_{a,b}\) 表示钦定 \(a\) 为出现最多的字符,\(b\) 为出现最少的字符的最大子段和(\(a\) 赋值为 \(1\)\(b\) 赋值为 \(-1\))。

你发现 \(f_{a,b}\) 的最终状态只与 \(a,b\) 的上一次状态有关,考虑 \(a = s_i\) 钦定 \(a\) 必选,那么有 \(f_{a,b} \larr f_{a,b} + 1\)

考虑 \(b\) 的选择,我们至少要选一个 \(b\),记 \(g_{a,b}\) 表示当前状态选或不选至少一个 \(b\),则 \(g_{b,a} = [f_{b,a} \geq 1]\)

其次考虑钦定 \(b\) 要选,那么有 \(f_{b,a} \larr \max(0, f_{b,a} - 1)\)

答案就是 \(\max\limits_{a}\max\limits_{b}{\max(0,f_{a,b} - !g_{a,b})}\)

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

string str;
bool g[30][30], apr[30];
int n, f[30][30], ans;
vector<int> chSet;

signed main() {
//	freopen ("hack2.in", "r", stdin);
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	cin >> n >> str;
	for (int i = 0; i < (int)str.size(); i ++) {
		int chVal = str[i] - 'a';
		if (!apr[chVal]) {
			chSet.emplace_back(chVal);
			apr[chVal] = true;
		}
	}
	
	for (int i = 0; i < (int)str.size(); i ++) {
		for (auto y : chSet) {
			int x = str[i] - 'a';
			if (x != y && y >= 0 && x >= 0) {
				f[x][y] ++;
				ans = max (ans, f[x][y] - (!g[x][y] ? 1 : 0));
				g[y][x] = (f[y][x] >= 1);
				f[y][x] = max (0, f[y][x] - 1);
			}
		}
	}
	cout << ans << '\n';
	return 0;
}

T3

本能的,对于 \(\left|x_j - x_i\right| \times (w_j + w_i)\),我们想要使其最小,首先 \(i,j\) 的间距不能很大,其次 \(w_i + w_j\) 的和不能太大。

\(lhs_i = \max\{j \mid j < i \wedge w_j \leq w_i\},rhs_i = \min\{j \mid j > i \wedge w_j \leq w_i\}\),我们借此限制了 \(\left|x_j - x_i\right|\) 在当前状态下最小,现在考虑如何限制 \(w_i + w_j\)

考虑当前解为 \((i,j)\),以下分情况讨论:

  • \(w_i \leq w_j\)

    • 可以证明取 \((i, lhs_j)\) 更优,因为 \(\left|x_{lhs_j} - x_i\right| < \left|x_j - x_i\right|\)\(w_i + w_{lhs_j} \leq w_i + w_j\),考虑将 \(lhs_j\) 作为新的 \(j\)
  • \(w_i > w_j\)

    • 可以证明取 \((rhs_i,j)\) 更优,因为 \(\left|x_j - x_{rhs_i}\right| < \left|x_j - x_i\right|\)\(w_j + w_{rhs_i} \leq w_i + w_j\),考虑将 \(rhs_i\) 作为新的 \(i\)

如此往复你会发现最优解一定是 \((lhs_i,i)\) 或者 \((i,rhs_i)\)

那么现在的问题相当于你有 \(2n\) 个三元组 \([l,r,v]\),询问区间 \([ql, qr]\) 中最小的 \(v\),考虑将询问离线下来,对于 \(l\)\([r,v]\),每次查询相当于单点查前缀最小,树状数组即可。

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

namespace FastIO {
	constexpr int SZ = (1 << 23);
	static int stkIO[33];
	char buf[SZ], *p1, *p2;
	
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, SZ, stdin), p1 == p2) ? EOF : *p1++)
	
	inline int read() {
		int res = 0, f = 1;
		char ch = getchar();
		while (!isdigit(ch)) f = ch == '-' ? -1 : 1, ch = getchar();
		while (isdigit(ch)) res = res * 10 + (ch ^ 48), ch = getchar();
		return res * f;
	}
	
	inline void write (int x) {
		int top = 0;
		if (x < 0) x = -x, putchar('-');
		do { stkIO[top++] = x % 10, x /= 10; } while(x);
		while(top) putchar(stkIO[--top] + '0');
	}
	
	inline void print (int x, char ch) {
		write(x), putchar(ch);
	}
}

using namespace std;
using namespace FastIO;
using pii = pair<int,int>;

constexpr int N = 6e5 + 10;
constexpr int inf = 0x3f3f3f3f3f3f3f3f;

vector<pii> ques[N], best[N];
int n, q, x[N], w[N], tree[N], stk[N], top, lhs[N], rhs[N], ans[N];

int calcValue (int p1, int p2) {
	return (w[p1] + w[p2]) * (x[p2] - x[p1]);
}

void addFWT (int p, int val) {
	for (; p <= n; p += (p & (-p))) {
		tree[p] = min(tree[p], val);
	}
}

int askFWT (int p) {
	int res = inf;
	for (; p; p -= (p & (-p))) {
		res = min(res, tree[p]);
	}
	return res;
}

signed main() {
	n = read(), q = read();
	memset (tree, 0x3f, sizeof(tree));
	for (int i = 1; i <= n; i ++) {
		x[i] = read(), w[i] = read();
	}
	
	for (int i = 1; i <= n; i ++) {
		while (top && w[stk[top]] > w[i]) top --;
		if (top) {
			lhs[i] = stk[top];
		}
		stk[++top] = i;
	}
	top = 0, memset (stk, 0, sizeof(stk));
	for (int i = n; i >= 1; i --) {
		while (top && w[stk[top]] > w[i]) top --;
		if (top) {
			rhs[i] = stk[top];
		}
		stk[++top] = i;
	}
	
	for (int i = 1; i <= n; i ++) {
		if (lhs[i]) {
			best[lhs[i]].push_back (make_pair(i, calcValue(lhs[i], i)));
		}
		if (rhs[i]) {
			best[i].push_back (make_pair(rhs[i], calcValue(i, rhs[i])));
		}
	}
	for (int i = 1; i <= q; i ++) {
		int l = read(), r = read();
		ques[l].push_back (make_pair(r, i));
	}
	
	for (int i = n; i >= 1; i --) {
		for (pii x : best[i]) {
			addFWT(x.first, x.second);
		}
		for (pii x : ques[i]) {
			ans[x.second] = askFWT(x.first);
		}
	}
	for (int i = 1; i <= q; i ++) {
		print(ans[i], '\n');
	}
	return 0;
}
posted @ 2025-06-30 20:59  xAlec  阅读(11)  评论(0)    收藏  举报