light5QAQ
文章11
标签10
分类6

文章分类

一言

文章归档

2025CSP-J复赛试题解析

2025CSP-J复赛试题解析

复赛没考好,写题解以泄愤

致敬传奇#Shang6Shan3Ruo3Shui3🫡

T1 拼数

题目传送门

**题意:**提取所有的数字并进行降序排列

方法比较多,例如全存到数组中进行排序,桶计数进行输出,或vector自动排序等。

数组排序方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
string s;
int a[N];
int main(){
//freopen("number.in","r",stdin);
//freopen("number.out","w",stdout);
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); //快读
cin>>s;
int len=s.size();
int cnt=0;
for(int i=0;i<len;i++){
if(s[i]>='0'&&s[i]<='9'){
a[++cnt]=s[i]-'0';
}
}
sort(a+1,a+cnt+1);
for(int i=cnt;i>=1;i--) cout<<a[i];
return 0;
}

T2 座位

题目传送门

**题意:**蛇形排座

既然是有规律的排座问题,显然可以用数学解决。不难发现需要讨论是单数列还是双数列,这样就可以知道是从前往后还是从后往前了。要注意输入先行后列,输出先列后行。

方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m;
int a[N];
int main(){
//freopen("seat.in","r",stdin);
//freopen("seat.out","w",stdout);
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); //快读
cin>>n>>m;
int r;//小R的成绩
cin>>r;
int cnt=0;
for(int i=2;i<=n*m;i++){
int num; //其他人的成绩
cin>>num;
if(num>r) cnt++; //记录小R前面的人数
}
cnt++; //cnt=小R的座位号
int a=cnt/n,b=cnt%n;
if(b==0){ //如果cnt恰好在边上
cout<<a<<" "; //列数即为a
if(a%2==0){ //偶数列从下往上
cout<<1; //行数
}else{ //奇数列从上往下
cout<<n; //行数
}
}else{ //否则
cout<<a+1<<" "; //列数即为a+1
if((a+1)%2==0){ //偶数列从下往上
cout<<n-b+1; //行数
}else{ //奇数列从上往下
cout<<b;
}
}

return 0;
}

T3 异或和

题目传送门

**题意:**找出异或和为k的区间的数量数

区间相关首先考虑前缀和(如果a xor b=cc xor a=b即异或为自身的逆运算),数量数相关考虑dp,

方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,k;
int a[N],b[N];
int f[N]; //前i个数的可能数
int l[1<<20+1]; //存储上一次出现异或和为i的位置
int main(){
//freopen("xor.in","r",stdin);
//freopen("xor.out","w",stdout);
ios::sync_with_stdio(false),cout.tie(0),cin.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]^b[i-1]; //异或前缀和
}
memset(l,-1,sizeof(l));
l[0]=0;
for(int i=1;i<=n;i++){
f[i]=f[i-1];
if(l[b[i]^k]>=0){ //如果存在一个位置使前缀和为k
f[i]=max(f[i],f[l[b[i]^k]]+1);
}
l[b[i]]=i;
}
cout<<f[n]<<endl;
return 0;
}

T4 多边形

题目传送门

**题意:**找出可以拼成多边形的木棍方案个数(即满足i=1mli>2×maxi=1mli {\textstyle \sum_{i=1}^{m}} \cdot l_i > 2 \times max^m_{i=1} \cdot l_i )。

不想写了 dp即可

本文作者:light5QAQ
本文链接:https://light5qaq.github.io/2025/11/09/2025CSP-J%E5%A4%8D%E8%B5%9B%E8%AF%95%E9%A2%98%E8%A7%A3%E6%9E%90/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可