2025CSP-S模拟赛20 比赛总结
2025CSP-S模拟赛20
我觉得还是加个分数比较好。。
| T1 | T2 | T3 | T4 |
|---|---|---|---|
| 0 | 0 | 20 | 0 |
排名:21/21;总分:20
今日神秘挂分。T1 交错代码挂了 50pts,T2 快写写炸了挂了 20pts。教训:不要快写了!有一种说法快写还没 printf 快!
T1 签
非常神秘。
考虑要合法需要满足两个条件:
- 奇数位上全是奇数,偶数位上全是偶数。这个是好理解的。
- 奇数位组成的序列的逆序对数量和偶数位组成的序列的逆序对数量之和是原序列的逆序对数量的三分之一。证明:对于一次操作而言,原序列逆序对数会减少 3,相应的奇数位序列逆序对数减少 1,或偶数位序列逆序对数减少 1。
然后就做完了。随便怎么统计一下就完
#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;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il 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;
}
#undef getchar()
}
using IO::read;
const int N = 3e5 + 10;
int n, a[N];
namespace BIT {
int c[N];
il void init() {
for (int i = 1; i <= n; i++) c[i] = 0;
}
il void update(int x, int v) {
for (int i = x; i <= n; i += (i & -i)) {
c[i] += v;
}
}
il int query(int x) {
int res = 0;
for (int i = x; i > 0; i -= (i & -i)) {
res += c[i];
}
return res;
}
il int query(int l, int r) {
return l <= r ? query(r) - query(l - 1) : 0;
}
}
il int solve() {
n = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
}
for (int i = 1; i <= n; i++) {
if (a[i] % 2 != i % 2) {
printf("No\n");
return 0;
}
}
BIT::init();
int cnt1 = 0;
for (int i = 1; i <= n; i += 2) {
cnt1 += BIT::query(a[i] + 1, n);
BIT::update(a[i], 1);
}
BIT::init();
int cnt2 = 0;
for (int i = 2; i <= n; i += 2) {
cnt2 += BIT::query(a[i] + 1, n);
BIT::update(a[i], 1);
}
BIT::init();
int cnt = 0;
for (int i = 1; i <= n; i++) {
cnt += BIT::query(a[i] + 1, n);
BIT::update(a[i], 1);
}
if ((cnt1 + cnt2) * 3 == cnt) {
printf("Yes\n");
} else {
printf("No\n");
}
return 0;
}
signed main() {
int qq = read();
while (qq--) {
solve();
}
return 0;
}
T2 数据结构基础练习题
考虑把询问和修改离线下来。考虑把修改进行差分,拆成两个后缀的修改,分别为 \((l,x,t)\) 和 \((r+1,-x,t)\),其中 \((pos,val,tim)\) 表示在时间 \(tim\) 时将 \([pos,n]\) 全部加上 \(val\)。
然后,考虑将询问和修改进行排序。位置为第一关键字,时间为第二关键字。
考虑枚举查询。当我们对于当前询问,把在这个询问之前的修改都类加上。然后对于当前询问统计答案即可。
放个核心代码。
sort(c + 1, c + 1 + cntc, cmp1);
sort(q + 1, q + 1 + cntq, cmp2);
int j = 1;
for (int i = 1; i <= cntq; i++) {
while (j <= cntc && (c[j].p < q[i].p || (c[j].p == q[i].p && c[j].t < q[i].t))) {
update(c[j].t, m, c[j].x);
j++;
}
ans[q[i].id] = kth(q[i].l, q[i].r, q[i].k);
}
然后这里的 update 和 kth 都暴力修改即可通过前两个包。
那然后就做完了呀。
直接考虑分块。
那么区间加就是简单的。考虑查询如何处理。对于每个块维护块内的数排序后的序列。询问时首先统计每个块内大于 \(x\) 的数,散块单独处理,整块直接二分。然后在外面在套一个二分即可求出第 \(k\) 大的数。
由于我们差分了,所以修改的那个数组应当开二倍。我本人因为没有开二倍调了五个小时。。
#include <bits/stdc++.h>
#define il inline
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))
il 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;
}
il void write(int x, bool t = 1) {
int top = 0;
x < 0 ? putchar('-'), x = -x : 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 = 7e4 + 10, M = 300, maxn = 7e7;
int n, m;
struct nodec {
int p, x, t;
} c[N * 2];
struct nodeq {
int p, l, r, k, t, id;
} q[N];
il bool cmp1(nodec a, nodec b) {return a.p != b.p ? a.p < b.p : a.t < b.t;}
il bool cmp2(nodeq a, nodeq b) {return a.p != b.p ? a.p < b.p : a.t < b.t;}
int a[N];
int B, bn, st[M], ed[M], bel[N];
int add[M];
il void init() {
B = 250, bn = 0;
st[0] = ed[0] = -1;
while (ed[bn] < m) {
bn++;
st[bn] = ed[bn - 1] + 1;
ed[bn] = min(ed[bn - 1] + B, m);
for (int i = st[bn]; i <= ed[bn]; i++) {
bel[i] = bn;
}
}
}
int d[N];
il void upd(int x) {
for (int i = st[bel[x]]; i <= ed[bel[x]]; i++) d[i] = a[i];
sort(d + st[bel[x]], d + ed[bel[x]] + 1);
}
il void update(int l, int r, int x) {
if (bel[l] == bel[r]) {
for (int i = l; i <= r; i++) a[i] += x;
upd(l);
return;
}
for (int i = l; i <= ed[bel[l]]; i++) a[i] += x; upd(l);
for (int i = st[bel[r]]; i <= r; i++) a[i] += x; upd(r);
for (int i = bel[l] + 1; i <= bel[r] - 1; i++) {
add[i] += x;
}
}
il int query(int l, int r, int x) {
if (bel[l] == bel[r]) {
int res = 0;
for (int i = l; i <= r; i++) res += (a[i] + add[bel[l]] <= x);
return res;
}
int res = 0;
for (int i = l; i <= ed[bel[l]]; i++) res += (a[i] + add[bel[l]] <= x);
for (int i = st[bel[r]]; i <= r; i++) res += (a[i] + add[bel[r]] <= x);
for (int i = bel[l] + 1; i <= bel[r] - 1; i++) {
int L = st[i], R = ed[i], ans = 0;
while (L <= R) {
int mid = L + R >> 1;
if (d[mid] + add[i] <= x) {
ans = mid;
L = mid + 1;
} else {
R = mid - 1;
}
}
if (ans) res += ans - st[i] + 1;
}
return res;
}
il int kth(int l, int r, int k) {
int L = -maxn, R = maxn, ans = 0;
while (L <= R) {
int mid = (L + R) >> 1;
if (query(l, r, mid) >= k) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return ans;
}
int ans[N];
int main() {
n = read(), m = read();
int cntc = 0, cntq = 0;
for (int i = 1; i <= m; i++) {
int op = read();
if (op == 0) {
int l = read(), r = read(), x = read();
c[++cntc] = {l, x, i};
c[++cntc] = {r + 1, -x, i};
} else {
int p = read(), l = read(), r = read(), k = read();
q[++cntq] = {p, l, r, k, i};
q[cntq].id = cntq;
}
}
sort(c + 1, c + 1 + cntc, cmp1);
sort(q + 1, q + 1 + cntq, cmp2);
init();
int j = 1;
for (int i = 1; i <= cntq; i++) {
while (j <= cntc && (c[j].p < q[i].p || (c[j].p == q[i].p && c[j].t < q[i].t))) {
update(c[j].t, m, c[j].x);
j++;
}
ans[q[i].id] = kth(q[i].l, q[i].r, q[i].k);
}
for (int i = 1; i <= cntq; i++) {
write(ans[i]);
}
return 0;
}

浙公网安备 33010602011771号