CSP-J2025题解
赛时挂爆了……
这篇题解不讲部分分
T1 拼数
没什么多说的,挺水的
纯暴力+桶排序(我当时顺手用了sort)
代码如下
#include<bits/stdc++.h>
using namespace std;
string s;
int a[1000001],cnt=0;
int main(){
cin.tie(0)->sync_with_stdio(0);
cin>>s;
int n=s.size();
for(int i=0;i<n;i++){
if('0'<=s[i]&&s[i]<='9'){
a[++cnt]=s[i]-'0';
}
}
sort(a+1,a+cnt+1);
for(int i=cnt;i;i--){
cout<<a[i];
}
}
T2 座位
wasser!
可以数学,也可以大模拟。(n,m只有10跟玩没区别)
代码如下
#include<bits/stdc++.h>
using namespace std;
int n,m,ans[15][15];
struct info{
int id,v;
}a[105];
bool cmp(info A,info B){
return A.v>B.v;
}
int main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n*m;i++){
cin>>a[i].v;
a[i].id=i;
}
sort(a+1,a+n*m+1,cmp);
int x=1,y=1;
bool dir=0;//0 down 1 up
for(int t=1;t<=n*m;t++){
ans[x][y]=a[t].id;
int nx=x,ny=y;
if(!dir) nx++;
else nx--;
if(nx<1){
ny++;
dir=!dir;
nx=1;
}else if(nx>n){
ny++;
dir=!dir;
nx=n;
}
x=nx,y=ny;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(ans[i][j]==1){
cout<<j<<' '<<i<<endl;
}
}
}
return 0;
}
T3 异或和
说实话这个题目想复杂了
首先,想求出一段异或和,不难想到前缀异或和。
我们可以注意到一个异或的特性
如果\(s_r⊕s_{l-1}=k\)
那么\(s_r⊕k=s_{l-1}\)
有了这个结论轻松多了。不难想到双指针。记lst为上一个区间的右端点,防止重叠。循环枚举右端点。设当前枚举到i,如果有\(s_x=s_i⊕k\),那么就把两lst更新为i,答案再加一。当然还要及一个pos数组i表示前缀和数组中结果为i的最靠右的位置在哪。每轮更新即可
代码如下
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=500005;
int n,k,a[N],s[N];
int pos[N*10];
signed main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) s[i]=s[i-1]^a[i];
memset(pos,-1,sizeof pos);
pos[0]=0;
int ans=0;int lst=0;
for(int i=1;i<=n;i++){
int x=s[i]^k;
if(pos[x]>=lst){
ans++;
lst=i;
}
pos[s[i]]=i;
}
cout<<ans<<endl;
}
T4 多边形
这个题目不难想到背包。
首先要排序,这样就不用管最大值了。
我们让\(dp_{i,j}\)表示前i个里面选出j个棍的方案数。发现边界条件是对于所有的i都有\(dp_{i,0}=1\)
转移方程如下
无论如何,都先有\(dp_{i,j}=dp_{i-1,j}\)
当\(j≥a_i\)是, \(dp_{i,j}=max(dp_{i,j},dp_{i-1,j-a_i})\)
然后统计答案,枚举i表示选出边得数量,然后统计有多少个和是大于当当前的值。那么这个做法爆空间。
我们发现,正难则反。如果求合法的范围太大(5000³),那么我们可以反着枚举不合法的。拿总共方案数得到最后的答案。这个时候就是一个组合数问题,写一个杨辉三角即可
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N=5005,mod=998244353;
int n,a[N],dp[N][N],c[N][N];
void init(){
c[1][1]=1;
for(int i=2;i<=5002;i++)//注意,一定要多算1个,保险5个!
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
int main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n;
init();
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for(int i=0;i<=n;i++) dp[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=5000;j++){
dp[i][j]=dp[i-1][j];
if(j>=a[i]) dp[i][j]=(dp[i][j]+dp[i-1][j-a[i]])%mod;
}
int ans=0;
for(int i=3;i<=n;i++){
for(int j=1;j<=i-1;j++) ans=(ans+c[i][j+1])%mod;
for(int j=1;j<=a[i];j++) ans=(ans-dp[i-1][j]+mod)%mod;
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号