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(); 
	}

}
posted @ 2025-12-31 03:17  LYET  阅读(0)  评论(0)    收藏  举报