CSP-J 2025题解

P14357 [CSP-J 2025] 拼数 / number(民间数据)

题目描述

小 R 正在学习字符串处理。小 X 给了小 R 一个字符串 sss,其中 sss 仅包含小写英文字母及数字,且包含至少一个 1∼91 \sim 919 中的数字。小 X 希望小 R 使用 sss 中的任意多个数字,按任意顺序拼成一个正整数。注意:小 R 可以选择 sss 中相同的数字,但每个数字只能使用一次。例如,若 sss1a01b\tt 1a01b1a01b,则小 R 可以同时选择第 1,3,41,3,41,3,4 个字符,分别为 1,0,11,0,11,0,1,拼成正整数 101101101110110110;但小 R 不能拼成正整数 111111111,因为 sss 仅包含两个数字 111。小 R 想知道,在他所有能拼成的正整数中,最大的是多少。你需要帮助小 R 求出他能拼成的正整数的最大值。

输入格式

输入的第一行包含一个字符串 sss,表示小 X 给小 R 的字符串。

输出格式

输出一行一个正整数,表示小 R 能拼成的正整数的最大值。

输入输出样例 #1

输入 #1

5

输出 #1

5

输入输出样例 #2

输入 #2

290es1q0

输出 #2

92100

说明/提示

【样例 2 解释】

sss 包含数字 2,9,0,1,02,9,0,1,02,9,0,1,0。可以证明,小 R 拼成的正整数的最大值为 921009210092100

【样例 3】

见选手目录下的 number/number3.innumber/number3.innumber/number3.innumber/number3.ansnumber/number3.ansnumber/number3.ans。该样例满足测试点 9∼119 \sim 11911 的约束条件。

【样例 4】

见选手目录下的 number/number4.innumber/number4.innumber/number4.innumber/number4.ansnumber/number4.ansnumber/number4.ans。该样例满足测试点 202020 的约束条件。

【数据范围】

∣s∣|s|s 为字符串 sss 的长度。对于所有测试数据,保证:

  • 1≤∣s∣≤1061 \leq |s| \leq 10^61s106
  • sss 仅包含小写英文字母及数字,且包含至少一个 1∼91 \sim 919 中的数字。

::cute-table{tuack}

测试点编号∣s∣≤\lvert s\rvert \leqs特殊性质
111111A
222222^
333^
444101010A
5,65,65,6^
7,87,87,810210^2102A
9∼119 \sim 11911^
12121210310^3103A
13,1413,1413,14^
15151510510^5105A
16,1716,1716,17^B
18,1918,1918,19^
20202010610^6106A
21,2221,2221,22^B
23∼2523 \sim 252325^
  • 特殊性质 A:sss 仅包含数字。
  • 特殊性质 B:sss 仅包含不超过 10310^3103 个数字。

思路

直接贪心即可,可以将所有的数字都拿出来,从大到小排序,必然最优。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long a[1000006];
string s;
int main(){
	cin>>s;
	for(int i=0;i<s.size();i++){
		if(s[i]>='0'&&s[i]<='9'){
			a[++a[0]]=(long long)(s[i]-'0');
		}
	}
	sort(a+1,a+a[0]+1);
	for(int i=a[0];i>=1;i--){
		cout<<a[i];
	}
	cout<<endl;
	return 0;
}

P14358 [CSP-J 2025] 座位 / seat(民间数据)

题目描述

CSP-J 2025 第二轮正在进行。小 R 所在的考场共有 n×mn \times mn×m 名考生,其中所有考生的 CSP-J 2025 第一轮成绩互不相同。所有 n×mn \times mn×m 名考生将按照 CSP-J 2025 第一轮的成绩,由高到低蛇形分配座位,排列成 nnn mmm 。具体地,设小 R 所在的考场的所有考生的成绩从高到低分别为 s1>s2>⋯>sn×ms_1 > s_2 > \dots > s_{n \times m}s1>s2>>sn×m,则成绩为 s1s_1s1 的考生的座位为第 1 111 ,成绩为 s2s_2s2 的考生的座位为第 111 222 …\dots,成绩为 sns_nsn 的考生的座位为第 111 nnn ,成绩为 sn+1s_{n+1}sn+1 的考生的座位为第 222 nnn …\dots,成绩为 s2ns_{2n}s2n 的考生的座位为第 222 111 ,成绩为 s2n+1s_{2n+1}s2n+1 的考生的座位为第 333 111 ,以此类推。

例如,若 n=4,m=5n = 4, m = 5n=4,m=5,则所有 4×5=204 \times 5 = 204×5=20 名考生将按照 CSP-J 2025 第一轮成绩从高到低的顺序,根据下图中的箭头顺序分配座位。

:::align{center}

:::

给定小 R 所在的考场座位的行数 nnn列数 mmm,以及小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩 a1,a2,…,an×ma_1, a_2, \dots, a_{n \times m}a1,a2,,an×m,其中 a1a_1a1 为小 R CSP-J 2025 第一轮的成绩,你需要帮助小 R 求出,他的座位为第几第几

输入格式

输入的第一行包含两个正整数 n,mn, mn,m,分别表示小 R 所在的考场座位的行数列数

输入的第二行包含 n×mn \times mn×m 个正整数 a1,a2,…,an×ma_1, a_2, \dots, a_{n \times m}a1,a2,,an×m,分别表示小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩,其中 a1a_1a1 为小 R CSP-J 2025 第一轮的成绩。

输出格式

输出一行两个正整数 c,rc, rc,r,表示小 R 的座位为第 ccc rrr

输入输出样例 #1

输入 #1

2 2
99 100 97 98

输出 #1

1 2

输入输出样例 #2

输入 #2

2 2
98 99 100 97

输出 #2

2 2

输入输出样例 #3

输入 #3

3 3
94 95 96 97 98 99 100 93 92

输出 #3

3 1

说明/提示

【样例 1 解释】

按照成绩从高到低的顺序,成绩为 100100100 的考生的座位为第 111 111 ,成绩为 999999 的考生的座位为第 111 222 ,成绩为 989898 的考生的座位为第 222 222 ,成绩为 979797 的考生的座位为第 222 111 。小 R 的成绩为 999999,因此座位为第 111 222

【样例 2 解释】

按照成绩从高到低的顺序,成绩为 100100100 的考生的座位为第 111 111 ,成绩为 999999 的考生的座位为第 111 222 ,成绩为 989898 的考生的座位为第 222 222 ,成绩为 979797 的考生的座位为第 222 111 。小 R 的成绩为 989898,因此座位为第 222 222

【数据范围】

对于所有测试数据,保证:

  • 1≤n≤101 \leq n \leq 101n10, 1≤m≤101 \leq m \leq 101m10;
  • 对于所有 1≤i≤n×m1 \leq i \leq n \times m1in×m,均有 1≤ai≤1001 \leq a_i \leq 1001ai100,且 a1,a2,…,an×ma_1, a_2, \dots, a_{n \times m}a1,a2,,an×m 互不相同。

::cute-table{tuack}

测试点编号n≤n \leqnm≤m \leqm特殊性质
111111111AB
2,32, 32,3^101010
4,54, 54,5101010111^
666222222A
777^^B
8,98, 98,9^^
101010^101010A
111111^^B
12∼1412 \sim 141214^^
15∼1715 \sim 171517101010222^
18∼2018 \sim 201820^101010^

特殊性质 A:对于所有 1≤i≤n×m1 \leq i \leq n \times m1in×m,均有 ai=ia_i = iai=i

特殊性质 B:对于所有 1≤i≤n×m1 \leq i \leq n \times m1in×m,均有 ai=n×m−i+1a_i = n \times m - i + 1ai=n×mi+1

思路

直接模拟放置,标记一下1点,扫到直接输出即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,d[105][105];
struct one{
	long long a,b;
}a[100005];
bool cmp(one a1,one b1){
	return a1.a>b1.a;
}
int main(){
	cin>>n>>m;
	cin>>a[1].a;
	a[1].b=1;
    for(int i=2;i<=n*m;i++){
		cin>>a[i].a;
		a[i].b=0;
	}
	sort(a+1,a+n*m+1,cmp);
	for(int i=1;i<=m;i++){
		if(i%2==1){
			for(int j=1;j<=n;j++){
				d[i][j]=a[(i-1)*n+j].b;
			}
		}
		else{
			for(int j=1;j<=n;j++){
				d[i][j]=a[(i-1)*n+n-j+1].b;
			}			
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(d[i][j]==1){
				cout<<i<<" "<<j<<endl;
				return 0;
			}
		}
	}
	return 0;
}

P14359 [CSP-J 2025] 异或和 / xor(民间数据)

题目描述

小 R 有一个长度为 nnn 的非负整数序列 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an。定义一个区间 [l,r][l, r][l,r] (1≤l≤r≤n1 \leq l \leq r \leq n1lrn) 的权值为 al,al+1,…,ara_l, a_{l+1}, \dots, a_ral,al+1,,ar 的二进制按位异或和,即 al⊕al+1⊕⋯⊕ara_l \oplus a_{l+1} \oplus \dots \oplus a_ralal+1ar,其中 ⊕\oplus 表示二进制按位异或。

小 X 给了小 R 一个非负整数 kkk。小 X 希望小 R 选择序列中尽可能多的不相交的区间,使得每个区间的权值均为 kkk。两个区间 [l1,r1],[l2,r2][l_1, r_1], [l_2, r_2][l1,r1],[l2,r2] 相交当且仅当两个区间同时包含至少一个相同的下标,即存在 1≤i≤n1 \leq i \leq n1in 使得 l1≤i≤r1l_1 \leq i \leq r_1l1ir1l2≤i≤r2l_2 \leq i \leq r_2l2ir2

例如,对于序列 [2,1,0,3][2, 1, 0, 3][2,1,0,3],若 k=2k = 2k=2,则小 R 可以选择区间 [1,1][1, 1][1,1] 和区间 [2,4][2, 4][2,4],权值分别为 2221⊕0⊕3=21 \oplus 0 \oplus 3 = 2103=2;若 k=3k = 3k=3,则小 R 可以选择区间 [1,2][1, 2][1,2] 和区间 [4,4][4, 4][4,4],权值分别为 1⊕2=31 \oplus 2 = 312=3333

你需要帮助小 R 求出他能选出的区间数量的最大值。

输入格式

输入的第一行包含两个非负整数 n,kn, kn,k,分别表示小 R 的序列长度和小 X 给小 R 的非负整数。

输入的第二行包含 nnn 个非负整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an,表示小 R 的序列。

输出格式

输出一行一个非负整数,表示小 R 能选出的区间数量的最大值。

输入输出样例 #1

输入 #1

4 2
2 1 0 3

输出 #1

2

输入输出样例 #2

输入 #2

4 3
2 1 0 3

输出 #2

2

输入输出样例 #3

输入 #3

4 0
2 1 0 3

输出 #3

1

说明/提示

【样例 1 解释】

小 R 可以选择区间 [1,1][1, 1][1,1] 和区间 [2,4][2, 4][2,4],异或和分别为 2221⊕0⊕3=21 \oplus 0 \oplus 3 = 2103=2。可以证明,小 R 能选出的区间数量的最大值为 222

【样例 2 解释】

小 R 可以选择区间 [1,2][1, 2][1,2] 和区间 [4,4][4, 4][4,4],异或和分别为 1⊕2=31 \oplus 2 = 312=3333。可以证明,小 R 能选出的区间数量的最大值为 222

【样例 3 解释】

小 R 可以选择区间 [3,3][3, 3][3,3],异或和为 000。可以证明,小 R 能选出的区间数量的最大值为 111。注意:小 R 不能同时选择区间 [3,3][3, 3][3,3] 和区间 [1,4][1, 4][1,4],因为这两个区间同时包含下标 333

【样例 4】

见选手目录下的 xor/xor4.inxor/xor4.inxor/xor4.inxor/xor4.ansxor/xor4.ansxor/xor4.ans

该样例满足测试点 4,54, 54,5 的约束条件。

【样例 5】

见选手目录下的 xor/xor5.inxor/xor5.inxor/xor5.inxor/xor5.ansxor/xor5.ansxor/xor5.ans

该样例满足测试点 9,109, 109,10 的约束条件。

【样例 6】

见选手目录下的 xor/xor6.inxor/xor6.inxor/xor6.inxor/xor6.ansxor/xor6.ansxor/xor6.ans

该样例满足测试点 14,1514, 1514,15 的约束条件。

【数据范围】

对于所有测试数据,保证:

  • 1≤n≤5×1051 \leq n \leq 5 \times 10^51n5×105, 0≤k<2200 \leq k < 2^{20}0k<220;
  • 对于所有 1≤i≤n1 \leq i \leq n1in,均有 0≤ai<2200 \leq a_i < 2^{20}0ai<220

::cute-table{tuack}

测试点编号n≤n \leqnkkk特殊性质
111222=0=0=0A
222101010≤1\leq 11B
33310210^2102=0=0=0A
4,54, 54,5^≤1\leq 11B
6∼86 \sim 868^≤255\leq 255255C
9,109, 109,1010310^3103^^
11,1211, 1211,12^<220< 2^{20}<220
1313132×1052 \times 10^52×105≤1\leq 11B
14,1514, 1514,15^≤255\leq 255255C
161616^<220< 2^{20}<220
1717175×1055 \times 10^55×105≤255\leq 255255C
18∼2018 \sim 201820^<220< 2^{20}<220

特殊性质 A: 对于所有 1≤i≤n1 \leq i \leq n1in,均有 ai=1a_i = 1ai=1

特殊性质 B: 对于所有 1≤i≤n1 \leq i \leq n1in,均有 0≤ai≤10 \leq a_i \leq 10ai1

特殊性质 C: 对于所有 1≤i≤n1 \leq i \leq n1in,均有 0≤ai≤2550 \leq a_i \leq 2550ai255

思路

稍微有些难度,首先,可以发现,我们可以统计以每个数开头的异或和为k的最小结尾,然后后缀取最小不断跳即可。
思考如何求,首先vector储存从1开始的前缀异或,然后对于每个数,求出前缀多少的才能使它达标,接着二分即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,k,a[500005],b[500005],c[500005],d,br=1,op=0;
vector<long long> v[2000006];
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i]=(b[i-1]^a[i]);
		v[b[i]].push_back(i);
	}
	for(int i=1;i<=n;i++){
		d=k^b[i-1];
		c[i]=n+1;
		if(v[d].size()!=0){
			long long l=0,r=v[d].size()-1,md=n+1;
			while(l<=r){
				long long mid=(l+r)/2;
				if(v[d][mid]>=i){
					md=min(md,v[d][mid]);
					r=mid-1;
				}
				else{
					l=mid+1;
				}
			}
			c[i]=md;
		}
	}
	c[n+1]=n+1;
	for(int i=n;i>=1;i--){
		c[i]=min(c[i],c[i+1]);
	}
	br=1;
	while(1){
		br=c[br];
		if(br>=n+1){
			break;
		}
		br++;
		op++;
		if(br>=n+1){
			break;
		}
	}
	cout<<op<<endl;
	return 0;
}

P14360 [CSP-J 2025] 多边形 / polygon(民间数据)

题目描述

小 R 喜欢玩小木棍。小 R 有 nnn 根小木棍,第 iii (1≤i≤n1 \leq i \leq n1in) 根小木棍的长度为 aia_iai

小 X 希望小 R 从这 nnn 根小木棍中选出若干根小木棍,将它们按任意顺序首尾相连拼成一个多边形。小 R 并不知道小木棍能拼成多边形的条件,于是小 X 直接将条件告诉了他:对于长度分别为 l1,l2,…,lml_1, l_2, \dots, l_ml1,l2,,lmmmm 根小木棍,这 mmm 根小木棍能拼成一个多边形当且仅当 m≥3m \geq 3m3 且所有小木棍的长度之和大于所有小木棍的长度最大值的两倍,即 ∑i=1mli>2×max⁡i=1mli\sum_{i=1}^{m} l_i > 2 \times \max_{i=1}^{m} l_ii=1mli>2×maxi=1mli

由于小 R 知道了小木棍能拼成多边形的条件,小 X 提出了一个更难的问题:有多少种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形?你需要帮助小 R 求出选出的小木棍能够拼成一个多边形的方案数。两种方案不同当且仅当选择的小木棍的下标集合不同,即存在 1≤i≤n1 \leq i \leq n1in,使得其中一种方案选择了第 iii 根小木棍,但另一种方案未选择。由于答案可能较大,你只需要求出答案对 998,244,353998,244,353998,244,353 取模后的结果。

输入格式

输入的第一行包含一个正整数 nnn,表示小 R 的小木棍的数量。

输入的第二行包含 nnn 个正整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,,an,表示小 R 的小木棍的长度。

输出格式

输出一行一个非负整数,表示小 R 选出的小木棍能够拼成一个多边形的方案数对 998,244,353998,244,353998,244,353 取模后的结果。

输入输出样例 #1

输入 #1

5
1 2 3 4 5

输出 #1

9

输入输出样例 #2

输入 #2

5
2 2 3 8 10

输出 #2

6

说明/提示

【样例 1 解释】

共有以下 999 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:

  1. 选择第 2,3,42, 3, 42,3,4 根小木棍,长度之和为 2+3+4=92 + 3 + 4 = 92+3+4=9,长度最大值为 444;
  2. 选择第 2,4,52, 4, 52,4,5 根小木棍,长度之和为 2+4+5=112 + 4 + 5 = 112+4+5=11,长度最大值为 555;
  3. 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+4+5=123 + 4 + 5 = 123+4+5=12,长度最大值为 555;
  4. 选择第 1,2,3,41, 2, 3, 41,2,3,4 根小木棍,长度之和为 1+2+3+4=101 + 2 + 3 + 4 = 101+2+3+4=10,长度最大值为 444;
  5. 选择第 1,2,3,51, 2, 3, 51,2,3,5 根小木棍,长度之和为 1+2+3+5=111 + 2 + 3 + 5 = 111+2+3+5=11,长度最大值为 555;
  6. 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 1+2+4+5=121 + 2 + 4 + 5 = 121+2+4+5=12,长度最大值为 555;
  7. 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 1+3+4+5=131 + 3 + 4 + 5 = 131+3+4+5=13,长度最大值为 555;
  8. 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+4+5=142 + 3 + 4 + 5 = 142+3+4+5=14,长度最大值为 555;
  9. 选择第 1,2,3,4,51, 2, 3, 4, 51,2,3,4,5 根小木棍,长度之和为 1+2+3+4+5=151 + 2 + 3 + 4 + 5 = 151+2+3+4+5=15,长度最大值为 555

【样例 2 解释】

共有以下 666 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:

  1. 选择第 1,2,31, 2, 31,2,3 根小木棍,长度之和为 2+2+3=72 + 2 + 3 = 72+2+3=7,长度最大值为 333;
  2. 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+8+10=213 + 8 + 10 = 213+8+10=21,长度最大值为 101010;
  3. 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 2+2+8+10=222 + 2 + 8 + 10 = 222+2+8+10=22,长度最大值为 101010;
  4. 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
  5. 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
  6. 选择第 1,2,3,4,51, 2, 3, 4, 51,2,3,4,5 根小木棍,长度之和为 2+2+3+8+10=252 + 2 + 3 + 8 + 10 = 252+2+3+8+10=25,长度最大值为 101010

【样例 3】

见选手目录下的 polygon/polygon3.inpolygon/polygon3.inpolygon/polygon3.inpolygon/polygon3.anspolygon/polygon3.anspolygon/polygon3.ans

该样例满足测试点 7∼107 \sim 10710 的约束条件。

【样例 4】

见选手目录下的 polygon/polygon4.inpolygon/polygon4.inpolygon/polygon4.inpolygon/polygon4.anspolygon/polygon4.anspolygon/polygon4.ans

该样例满足测试点 11∼1411 \sim 141114 的约束条件。

【子任务】

对于所有测试数据,保证:

  • 3≤n≤5,0003 \leq n \leq 5,0003n5,000;
  • 对于所有 1≤i≤n1 \leq i \leq n1in,均有 1≤ai≤5 0001 \leq a_i \leq 5\,0001ai5000

::cute-table{tuack}

测试点编号n≤n \leqnmax⁡i=1nai≤\max_{i=1}^{n} a_i \leqmaxi=1nai
1∼31 \sim 313333101010
4∼64 \sim 64610101010210^2102
7∼107 \sim 10710202020^
11∼1411 \sim 141114500500500^
15∼1715 \sim 171517^111
18∼2018 \sim 2018205 0005\,0005000^
21∼2521 \sim 252125^5 0005\,0005000

思路

首先想到暴力枚举使用,可得40分。
然后考虑优化,使用前后缀背包DP,可以发现,有不成立仅当前后之和小于等与aia_iai所以前后缀背包DP,记录可能性,再给其中一个前缀和,在枚举统计即可,最后直接容斥即可。

代码见下

#include<bits/stdc++.h>
using namespace std;
int n,a[5005],mod=998244353,f[5005][5005],f2[5005][5005],dl=0,de=0,op=0,kl=0;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	f[0][0]=1;
	for(int i=0;i<=n-1;i++){
		for(int j=5001;j>=0;j--){
			f[i+1][j]=f[i][j];
			if(j+a[i+1]<=5000){
				f[i+1][j+a[i+1]]=(f[i+1][j+a[i+1]]+f[i][j])%mod;
			}
			else{
				f[i+1][5001]=(f[i+1][5001]+f[i][j])%mod;
			}
		}
	}
	f2[n+1][0]=1;
	for(int i=n+1;i>=2;i--){
		for(int j=5001;j>=0;j--){
			f2[i-1][j]=f2[i][j];
			if(j+a[i-1]<=5000){
				f2[i-1][j+a[i-1]]=(f2[i-1][j+a[i-1]]+f2[i][j])%mod;
			}
			else{
				f2[i-1][5001]=(f2[i-1][5001]+f2[i][j])%mod;
			}
		}
	}
	for(int i=n+1;i>=1;i--){
		for(int j=1;j<=5001;j++){
			f2[i][j]=(f2[i][j]+f2[i][j-1])%mod;
		}
	}
	dl=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i]>=a[j]&&i!=j){
				dl++;
			}
		}
	}
	dl+=n;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=a[i];j++){
			op=(op+(long long)f[i-1][j]*f2[i+1][a[i]-j])%mod;
		}
	}
	de=1;
	for(int i=1;i<=n;i++){
		de=(de*2)%mod;
	}
	de-=n*(n-1)/2;
	de-=n;
	de--;
	de=(de+mod)%mod;
	//cout<<de<<endl;
	kl=(de+dl-op+mod)%mod;
	cout<<kl<<endl;
	return 0;
}
posted @ 2025-11-03 16:58  bz02_2023f2  阅读(5)  评论(0)    收藏  举报  来源