1 2025 02 07 模拟赛总结
写于2025年2月9日
成绩表
依旧是被TZK大神爆杀的一天
![[photo/Pasted image 20250209163626.png]]
做题情况
- T1:签到题,没什么好说的(100)
- T2:以为自己是正解,但只拿到30pts,正解要复杂一些(30)
- T3:实际上这题比较简单、可做,但赛场上没什么自信(时间)去想正解,于是直接打了暴力(30)
- T4:子区间颜色数和的问题,不会做,赛后看题解也没有看懂,等以后学了莫队回来补(30)
赛时心态
感觉比赛时有些紧张,但还好,因为是模拟赛,而且第一题是一个签到题,看了一眼就知道怎么做了。在做第二题时遇到了困难,因为题面以及样例解释都给错了,导致卡了一段时间,最后想出了自己以为是正解的解法。所以做第二题时稍微有点慌。T3、T4因为之前从来没有做出来过,所以看了一眼没有思路就直接开始打暴力。最后T4的暴力差点没写出来,那时候是真慌了,差点放弃。
总结
优点
会的题都做对了,不会的题也打了暴力,拿到了暴力分,没有放弃打T4的暴力
缺点
做题经验不足,T2和T3其实是有机会想出来的,但是缺乏经验,做T3时心态有些急躁了(或者说没有信心做T3),因而没有敢去想正解
题面及题解
T1
![[photo/Pasted image 20250209165521.png]]
没什么好说的,直接看AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int h[N], ver[N << 1], ne[N << 1], tot;
int siz[N], ans1[N], ans2[N];
void add(int x, int y){
ver[++tot] = y;
ne[tot] = h[x];
h[x] = tot;
}
void dfs(int x, int fa){
siz[x] = 1;
ans1[x] = ans1[fa] + 1;
for(int i = h[x]; i; i = ne[i]){
int y = ver[i];
if(y == fa) continue;
dfs(y, x);
siz[x] += siz[y];
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i < n; i++){
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs(1, 0);
for(int i = 1; i <= n; i++){
printf("%d %d\n", ans1[i], n - siz[i] + 1);
}
return 0;
}
T2
原题:Problem - I - Codeforces
赛时题面太抽象
给定一个长度为n的正整数序列,定义一个区间的权值为区间内出现的不同数字的数量减去区间mex
,一个区间的mex
为这个区间内最小的没有出现过的正整数。你需要选出一个非空子区间使得权值最大。
样例:
![[photo/Pasted image 20250209170135.png]]
大致思路:枚举可能的mex,根据mex将原序列分段,然后在这些分开的段中找出不同数字数目最多的减去mex,ans再和它取最大即可。
ACcode:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
using namespace std;
const int N = 2e5 + 10, inf = 1 << 29;
int n, m;
int a[N], t[N], v[N];
vector<vector<int>> dic(N);
struct que{
int l, r, mex;
bool operator < (const que &o) const { return r < o.r; }
};
vector<que> ask;
int read(){
int ret = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
ret = ret * 10 + c - '0';
c = getchar();
}
return ret * f;
}
void modify(int x, int d){
for(; x <= n; x += x & -x) t[x] += d;
}
int query(int x){
int ret = 0;
for(; x > 0; x -= x & -x) ret += t[x];
return ret;
}
int main(){
//freopen("test.in","r",stdin);
n = read(), m = read();
for(int i = 1; i <= n; i++){
a[i] = read();
if(a[i] <= n) dic[a[i]].push_back(i);
}
int cnt = 0;
for(int i = 1; i <= n + 1; i++){
if(dic[i].size()){
int pre = 1;
for(auto r : dic[i]){
if(r - 1 >= pre){
ask.push_back({pre, r - 1, i});
}
pre = r + 1;
}
if(pre <= n){
ask.push_back({pre, n, i});
}
} else {
ask.push_back({1, n, i});
break;
}
}
sort(ask.begin(), ask.end());
int lal = 1;
int ans = -inf;
for(auto [l, r, mex] : ask){
for(int j = lal; j <= r; j++){
if(v[a[j]]) modify(v[a[j]], -1);
v[a[j]] = j;
modify(j, 1);
}
lal = r + 1;
ans = max(query(r) - query(l - 1) - mex, ans);
}
printf("%d\n",ans);
return 0;
}
T3
原题:Problem - I - Codeforces
![[photo/Pasted image 20250209170605.png]]
这个题感觉根本没有我想象中T3的难度,但赛时感觉很难。
考虑\(a_i > a_{i+1}\),那么i后面必须被划分开。这也就意味着所有的漂亮划分的k都是i的因子。
所以使用一个线段树维护所有\(a_i > a_{i+1}\)位置的i,求它们的最大公因数,答案就是最大公因数的因数数量。直接用线段树维护一个区间gcd即可,注意gcd = 0的情况,某人因为这一点挂了100
ACcode:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N = 1e5 + 10;
int T, n, m;
int a[N], cnt[N];
struct node{
int l, r, dat;
}t[N << 2];
int read(){
int ret = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
ret = ret * 10 + c - '0';
c = getchar();
}
return ret * f;
}
void calc(){
for(int i = 1; i <= N - 10; i++){
for(int j = i; j <= N - 10; j += i){
cnt[j]++;
}
}
}
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a % b);
}
void build(int p, int l, int r){
t[p].l = l, t[p].r = r;
if(l == r){
t[p].dat = (a[l] > a[l + 1] && l < n) ? l : 0;
return;
}
int mid = l + r >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
t[p].dat = gcd(t[p << 1].dat, t[p << 1 | 1].dat);
}
void modify(int p, int l, int r, int x, int v){
if(l == r){
t[p].dat = v;
return;
}
int mid = l + r >> 1;
if(x <= mid) modify(p << 1, l, mid, x, v);
else modify(p << 1 | 1, mid + 1, r, x, v);
t[p].dat = gcd(t[p << 1].dat, t[p << 1 | 1].dat);
}
void solve(){
n = read(), m = read();
cnt[0] = n;
for(int i = 1; i <= n; i++) a[i] = read();
build(1, 1, n);
printf("%d\n", cnt[t[1].dat]);
//printf("t[1].dat: %d\n", t[1].dat);
for(int i = 1; i <= m; i++){
int x = read(), v = read();
a[x] = v;
if(x > 1){
modify(1, 1, n, x - 1, (a[x - 1] > a[x] ? x - 1 : 0));
}
if(x < n){
modify(1, 1, n, x, (a[x] > a[x + 1] ? x : 0));
}
printf("%d\n", cnt[t[1].dat]);
//printf("t[1].dat: %d\n", t[1].dat);
}
}
int main(){
//freopen("test.in","r",stdin);
calc();
int T = 1;
while(T--){
solve();
}
}
T4
原题:Dashboard - 2023 Xian Jiaotong University Programming Contest - Codeforces(J题,但是打不开)
![[photo/Pasted image 20250209171334.png]]
![[photo/Pasted image 20250209171727.png]]
ACcode(莫队,网上的,我没写):
#include "bits/stdc++.h"
using namespace std;
using i64 = long long;
using u32 = unsigned int;
constexpr int N = 2E6;
int cnt[N + 1];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
a[i]--;
}
vector<int> p(n, -1);
vector<int> pre(n, -1);
for (int i = 0; i < n; i++) {
pre[i] = p[a[i]];
p[a[i]] = i;
}
p.assign(n, n);
vector<int> nex(n, n);
for (int i = n - 1; i >= 0; i--) {
nex[i] = p[a[i]];
p[a[i]] = i;
}
struct node {
int l, r, id;
};
vector<node> q(m);
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
l--, r--;
q[i] = { l, r, i };
}
int bk = sqrt(m);
sort(q.begin(), q.end(), [&](node a, node b) {
return ((a.l / bk) ^ (b.l / bk)) ? a.l < b.l : (((a.l / bk) & 1) ? a.r < b.r : a.r > b.r);
});
int l = 0, r = -1;
u32 res = 0;
u32 Lres = 0, Rres = 0;
u32 Cnt = 0;
vector<u32> ans(m);
auto add = [&](int pos, bool flag) {
int num = a[pos];
++cnt[num];
if (cnt[num] == 1) {
++Cnt;
}
if (flag) {
Rres += pos - max(pre[pos], l - 1);
res += Rres;
Lres += Cnt;
} else {
Lres += min(r, nex[pos] - 1) - pos + 1;
res += Lres;
Rres += Cnt;
}
};
auto del = [&](int pos, bool flag) {
int num = a[pos];
if (flag) {
res -= Rres;
Lres -= Cnt;
Rres -= pos - max(pre[pos], l - 1);
} else {
res -= Lres;
Rres -= Cnt;
Lres -= min(r, nex[pos] - 1) - pos + 1;
}
--cnt[num];
if (cnt[num] == 0) {
--Cnt;
}
};
for (int i = 0; i < m; i++) {
auto &[ql, qr, qid] = q[i];
while (r < qr) add(++r, 1);
while (l > ql) add(--l, 0);
while (l < ql) del(l++, 0);
while (r > qr) del(r--, 1);
ans[qid] = res;
}
for (int i = 0; i < m; i++) {
cout << ans[i] << '\n';
}
return 0;
}