CSP-J 2025
P14357 [CSP-J 2025] 拼数
把字符串中的所有数字找出来,从大到小排序输出即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
string s;
cin>>s;
priority_queue<char> q;
for(auto ch:s){
if(ch>='0' && ch<='9'){
q.push(ch);
}
}
while(q.size()){
cout<<q.top();
q.pop();
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
P14358 [CSP-J 2025] 座位
简单但恶心的题,找到排序之后的排名,直接去找位置
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,m;
cin>>n>>m;
vector<int> a(n*m+1);
int x;
for(int i=1;i<=n*m;i++){
cin>>a[i];
}
x=a[1];
sort(a.begin()+1,a.end(),greater<int>());
int idx=0;
for(int i=1;i<=n*m;i++){
if(a[i]==x) idx=i;
}
int cnt=idx/n;
idx%=n;
if(idx==0){
cout<<cnt<<" "<<((cnt&1)?n:1);
}
else{
cout<<cnt+1<<" "<<((cnt&1)?n-idx+1:idx);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
P14359 [CSP-J 2025] 异或和
直接从前往后循环,用 set 维护前缀的异或值。如果到某个位置,发现以当前位置结尾,可以和之前在 set 中的某一个位置凑出 \(k\)。所以,以当前位置为 \(r\),前面某个位置为 \(l\) 的区间是一个合法区间,在当前位置可以切一刀,同时清空 set。
我们不用关心 \(l\) 的具体位置,因为无论如何都要在当前位置切,切清空 set,所以 \(l\) 具体在哪里,对后面不会造成影响
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
map<int,int> mp;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0,now=0;
mp[0]=1;
for(int i=1;i<=n;i++){
now^=a[i];
if(mp[now^k]){
ans++;
mp.clear();
mp[0]=1;
now=0;
}
else{
mp[now]++;
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}
P14360 [CSP-J 2025] 多边形
先将 \(a\) 数组从小到大排序。
假设选了 \(m\) 个数,\(b_1,b_2,b_3,...,b_m\)
这 \(m\) 个数符合条件,当且仅当 \(b_1+b_2+b_3+..+b_{m-1}<b_m\)
所以,考虑 DP,设 \(f[i][j]\) 表示,从前 \(i\) 个数中选,且总和不超过 \(j\) 的方案数。
如何统计答案?
枚举最后一个数,让 \(a_i\) 做为某个合法序列的最后一个数,统计此时的方案数量
此时的方案数量为,从前 \(i-1\) 个数中选,且总和大于 \(a_i\) 的方案数,显然,对 DP 的状态求和即可
注意,\(f[i][j]\) 的 \(j\) 可能会很大,但因为数值最大是 5000,所以所有 \(j>5000\) 的值,都统一计入 \(j=5001\) 的状态中。
注意,合法序列要求最少有三个数,所以还需要把一些两个数的方案排除掉;但因为 \(a\) 是从小到大排序,所以不会有合法的两个数的方案,所以无需做这一步。
DP 就是一个类似于背包的东西,是容易的。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a.begin()+1,a.end());
vector<vector<int>> f(n+1,vector<int>(5010));
//从前i个选,且总和等于j的方案数
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=5001;j++){
f[i][j]=f[i-1][j];
}
for(int j=0;j<=5001;j++){
int w=min(5001ll,a[i]+j);
f[i][w]+=f[i-1][j];
f[i][w]%=mod;
}
}
int ans=0;
for(int i=3;i<=n;i++){
//以第i个为最大的,从前i-1个中选,总和大于a[i]的方案数
for(int j=a[i]+1;j<=5001;j++){
ans+=f[i-1][j];
ans%=mod;
}
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
}

浙公网安备 33010602011771号