2025 CSP-S 模拟赛 12
2025 CSP-S 模拟赛 12
倒序放题吗,有点意思。
得分
| T1 | T2 | T3 | T4 | Sum | Rank |
|---|---|---|---|---|---|
| \(100\) | \(20\) | \(23\) | \(100\) | \(243\) | \(3/19\) |
题解
T1 环游
容易发现 \(V\) 只会变化 \(\log V\) 次,每一次变化后我们可以走完一个连续的区间,最后要求我们走完整个区间。
把每一次变化看成一层,先不考虑没变的时候,在剩下的层中进行状压 dp。令 \(f_S\) 表示选完了 \(S\) 这些层,可以选出的最长前缀。\(g_S\) 类似的表示后缀。转移比较简单,复杂度 \(O(V\log V)\)。
处理答案的时候先枚举前缀取的层,然后得出后缀取的层,根据 \(f_S\) 和 \(g_T\) 求出它们可以给第一层中的那个连续段做贡献,那么这个连续段的答案就知道了。总复杂度是 \(O(V\log V)\) 的。
代码实现可能多了个老哥:
#include <bits/stdc++.h>
#define il inline
#define int long long
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 5e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int n, V;
int x[Maxn], d[Maxn];
int v[Maxn], m;
int cnt[20], l[20][Maxn], r[20][Maxn];
int ans[Maxn];
int U, f[1 << 18], g[1 << 18];
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
signed main() {
read(n), read(V);
for(int i = 1; i <= n; i++) read(x[i]);
x[0] = -Inf, x[n + 1] = Inf;
for(int i = 0; i <= n; i++) d[i] = x[i + 1] - x[i];
while(V) v[m++] = V, V >>= 1;
v[m] = 0;
for(int i = 0; i <= m; i++) {
for(int j = 1; j <= n; j++) {
if(d[j - 1] > v[i]) cnt[i]++, l[i][cnt[i]] = j;
if(d[j] > v[i]) r[i][cnt[i]] = j;
}
}
int U = (1 << m);
for(int i = 0; i < U; i++) f[i] = 0, g[i] = n + 1;
for(int i = 0; i < U; i++) {
for(int j = 1; j <= m; j++) {
if(i >> j - 1 & 1) continue;
int p = upper_bound(l[j] + 1, l[j] + cnt[j] + 1, f[i]) - l[j] - 1;
if(f[i] == l[j][p + 1] - 1) chkmax(f[i | (1 << j - 1)], r[j][p + 1]);
else chkmax(f[i | (1 << j - 1)], r[j][p]);
}
}
for(int i = 0; i < U; i++) {
for(int j = 1; j <= m; j++) {
if(i >> j - 1 & 1) continue;
int p = lower_bound(r[j] + 1, r[j] + cnt[j] + 1, g[i]) - r[j];
if(g[i] == r[j][p - 1] + 1) chkmin(g[i | (1 << j - 1)], l[j][p - 1]);
else chkmin(g[i | (1 << j - 1)], l[j][p]);
}
}
int flg = 0;
for(int i = 0; i < U; i++) {
int S = i, T = (U - 1) ^ i;
if(f[S] >= g[T]) flg = 1;
else {
int p = upper_bound(l[0] + 1, l[0] + cnt[0] + 1, f[i]) - l[0] - 1;
if(f[S] == l[0][p + 1] - 1) p++;
if(g[T] <= r[0][p] + 1) ans[p] = 1;
}
}
for(int i = 1; i <= cnt[0]; i++) {
for(int j = l[0][i]; j <= r[0][i]; j++) {
if(ans[i] || flg) puts("Possible");
else puts("Impossible");
}
}
Usd();
return 0;
}
T2 数塔
看到中位数先考虑二分答案,用经典套路把原序列转化为 \(01\) 序列,然后只需要求出顶上的数字是 \(0\) 还是 \(1\) 即可。
考虑一个 \(01\) 交替连续段,如果两端颜色相同则这一段颜色都是这个,否则会分成左边一半和右边一半同色。找出中间位置所属的连续段并求解即可。复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define il inline
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int T;
int n, m, a[Maxn];
int c[Maxn];
il int check(int mid) {
for(int i = 1; i <= m; i++) c[i] = (a[i] >= mid);
int ans1 = n - 1, ans2 = n - 1;
for(int i = n; i >= 2; i--) {
if(c[i] == c[i - 1]) {ans1 = n - i; break;}
}
for(int i = n; i < m; i++) {
if(c[i] == c[i + 1]) {ans2 = i - n; break;}
}
int ans = min(ans1, ans2);
if(ans & 1) return !c[n];
else return c[n];
}
il void solve() {
read(n); m = (n << 1) - 1;
for(int i = 1; i <= m; i++) read(a[i]);
int l = 1, r = m, res = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) l = mid + 1, res = mid;
else r = mid - 1;
}
write(res);
}
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
read(T);
while(T--) solve();
Usd();
return 0;
}
T3 二择
注意到大小为 \(n\) 的匹配和大小为 \(n\) 的独立集加起来正好 \(3n\) 个点。所以我们找出原图的一个极大匹配,此时没有被选中的点必然构成一个独立集。这两部分必有一个满足条件,输出即可。
#include <bits/stdc++.h>
#define il inline
using namespace std;
const int Maxn = 5e5 + 5;
const int Inf = 2e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);//dzbql
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int T;
int n, m;
int vis[Maxn], id[Maxn], cnt;
il void solve() {
for(int i = 1; i <= 3 * n; i++) vis[i] = 0;
read(n), read(m);
cnt = 0;
for(int i = 1, u, v; i <= m; i++) {
read(u), read(v);
if(!vis[u] && !vis[v]) id[++cnt] = i, vis[u] = vis[v] = 1;
}
if(cnt >= n) {
puts("Beta2");
for(int i = 1; i <= n; i++) write(id[i], 0); puts("");
}
else {
puts("Beta1");
cnt = 0;
for(int i = 1; i <= 3 * n; i++) if(!vis[i]) id[++cnt] = i;
for(int i = 1; i <= n; i++) write(id[i], 0); puts("");
}
}
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
read(T);
while(T--) solve();
Usd();
return 0;
}
T4 平衡
找规律。\(n\) 为偶数无解,\(n\) 为奇数仿照样例放一下即可。
#include <bits/stdc++.h>
#define il inline
using namespace std;
const int Maxn = 1e6 + 5;
const int Inf = 2e9;
template <typename T> il void chkmax(T &x, T y) {x = (x >= y ? x : y);}
template <typename T> il void chkmin(T &x, T y) {x = (x <= y ? x : y);}
template <typename T>
il void read(T &x) {
x = 0; char ch = getchar(); bool flg = 0;
for(; ch < '0' || ch > '9'; ch = getchar()) flg = (ch == '-');
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
flg ? x = -x : 0;
}
template <typename T>
il void write(T x, bool typ = 1) {
static short Stk[50], Top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do Stk[++Top] = x % 10, x /= 10; while(x);
while(Top) putchar(Stk[Top--] | 48);
typ ? putchar('\n') : putchar(' ');
}
il void IOS() {ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);}
il void File() {freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);}
bool Beg;
int T;
int n, a[Maxn];
il void solve() {
read(n);
if(n % 2 == 0) {puts("NO"); return ;}
puts("YES");
int pos = n + 1;
for(int i = 1; i <= n; i++) {
int p1 = pos, p2 = (pos > n ? pos - n : pos + n);
a[p1] = (i << 1) - 1, a[p2] = (i << 1);
pos = p2 + 1;
}
for(int i = 1; i <= (n << 1); i++) write(a[i], 0);
putchar('\n');
}
bool End;
il void Usd() {cerr << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n"; }
int main() {
read(T);
while(T--) solve();
Usd();
return 0;
}

浙公网安备 33010602011771号