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;
}

浙公网安备 33010602011771号