CSP-J 2025 题解

最水CSP-J,AK了,写题解来记录一下。

number

首先把所有数字数量记一下,因为贪心,肯定要大数字放前面,类似998887777...111000。做完了。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define endl '\n'

int cnt[20];
string s; 

signed main() {
	std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> s;
	int n = s.length();
	s = " " + s;
	for (int i = 1; i <= n; i++) {
		if ('0' <= s[i] && s[i] <= '9') cnt[s[i] - '0']++;
	}
	for (int i = 9; i >= 0; i--) {
		for (int j = 1; j <= cnt[i]; j++) {
			cout << i;
		}
	}
	return 0;
}

seat

按题意模拟即可。注意输入和输出行列顺序不一样。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define endl '\n'

int n, m, R;
struct node {
	int s, xb;
} a[100005];

bool cmp(node x, node y) {
	return x.s > y.s;
}

struct edge {
	int x, y;
} ans[100005];
int tot;

signed main() {
	std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n * m; i++) {
		cin >> a[i].s;
		a[i].xb = i;
	}
	sort(a + 1, a + n * m + 1, cmp);
	
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			if (i & 1) ans[++tot] = {i, j};
			else ans[++tot] = {i, n - j + 1};
		}
	}
	for (int i = 1; i <= n * m; i++) {
		if (a[i].xb == 1) {
			R = i;
			break;
		}
	}
	cout << ans[R].x << ' ' << ans[R].y << endl;
	return 0;
}

xor

看到区间异或,先处理前缀异或数组 \(q\),这样就能 \(O(1)\) 求区间异或值了。

假设上一个区间为 \([l,r]\),贪心的,为了让区间尽可能多,新的区间 \([l',r']\) 需要满足 \(l'>r\)\(r'\) 最小。所以扫一遍前缀异或数组,当扫到 \(i\) 时,判断是否存在 \(l' \in (r,i]\) 使得 \(q_i \oplus q_{l'-1}=k\),如果存在则累加答案,并更新最新区间的右端点。可以用一个 \(\operatorname{set}\) 来存 \(q_{r+1},q_{r+2},...,q_{i}\),用来快速判断。详见代码。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define endl '\n'

int n, k, a[500005], q[500005], ans;
set <int> s;

signed main() {
	std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		q[i] = q[i - 1] ^ a[i]; 
	}
	s.insert(0);
	for (int i = 1; i <= n; i++) {
		if (s.count(q[i] ^ k)) {
			ans++;
			s.clear();
		}
		s.insert(q[i]);
	}
	cout << ans << endl;
	return 0;
}

polygon

简单01背包,从小到大排序并依次扫每个木棍,假设扫到 \(i\),则此时只考虑选用 \([1,i]\) 中的木棍。最大的木棍就是扫到的木棍。转移时对于每个木棍可以先计算取的情况,累加答案后再计算不取的情况。注意到木棍最大值不超过 \(5000\),所以 dp 数组第二维开到 \(10004\) 就足够了。大于等于 \(10004\) 的全放到 \(10004\) 里存。

少于三根的情况可以发现是不满足题目中其他条件的,不用考虑。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define endl '\n'

const int p = 998244353; 
const int Max = 10004;
int n, a[5005], f[5005][10005], ans;

signed main() {
	std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	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 = 1; i <= n; i++) {
		for (int j = 0; j <= Max; j++) {
			f[i][min(j + a[i], Max)] = (f[i][min(j + a[i], Max)] + f[i - 1][j]) % p;
		}
		for (int j = 2 * a[i] + 1; j <= Max; j++) ans = (ans + f[i][j]) % p;
		for (int j = 0; j <= Max; j++) f[i][j] = (f[i][j] + f[i - 1][j]) % p;
	}
	cout << ans << endl;
	return 0;
}
posted @ 2025-11-22 20:56  wwqwq  阅读(8)  评论(0)    收藏  举报