2025.7.29 CSP-S模拟赛29
日期和比赛编号竟然同步了(喜
rk6,还不错,不过和前五几乎断层了
T1 二分图匹配
考试前半个小时读错了题意,比较糖;
简单dp,设 \(dp_{i,j}\) 表示序列 a 的前 \(i\) 个字符,匹配了 \(j\) 个的情况在 b 序列上的最小结束位置,用一个动态数组 \(q\) 存下每个字母在 b 序列中的位置;转移时枚举 \(i\) 和 \(j<=i\) ,二分出当前位置上字母的位置序列中,位置最小大于 \(dp_{i-1,j-1}\) 的,设其位置为 \(x\) ,那么可得转移方程:\(dp_{i,j}=min(dp_{i-1,j},x)\) ,时间复杂度 \(O(n^2logn)\) ,具体可见代码;
#include<bits/stdc++.h>
using namespace std;
int n,m,sum;
char c;bool flag=1;
char a[1005],b[1000005];
vector<int> q[30];
int siz[30];
int dp[1005][1005],ans;
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
siz[a[i]-'A']++;
if(i==1) c=a[i];
else if(a[i]!=c) flag=0;
}
for(int j=1;j<=m;j++){
cin>>b[j];
q[b[j]-'A'].push_back(j);
}
int xb=0;
memset(dp,0x3f3f3f3f,sizeof dp);
dp[0][0]=0;
for(int i=1;i<=n;i++){
dp[i][0]=0;
for(int j=1;j<=i;j++){
dp[i][j]=dp[i-1][j];
int xb=upper_bound(q[a[i]-'A'].begin(),q[a[i]-'A'].end(),dp[i-1][j-1])-q[a[i]-'A'].begin();
if(xb<q[a[i]-'A'].size()) dp[i][j]=min(dp[i][j],q[a[i]-'A'][xb]);
}
}
for(int i=1;i<=n;i++){
if(dp[n][i]<=m) ans=i;
}
cout<<ans;
return 0;
}
T2 虚图
使用牛子儒大佬的时间复杂度 \(O(n)\) 做法,思路是bfs,对于非关键点维护距离它最近的关键点和距离它第二近的关键点即距离,两个距离相加去最小值就是结果,但是要注意特判关键点之间有直接连边的情况,下面放代码;
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
#define int long long
int T,n,m,lst,ans=1e18;
int flag[MAXN];
struct node{
int pos,dis;
};
bool cmp(node a,node b){
return a.pos<b.pos;
}
int mf[MAXN],ms[MAXN],posf[MAXN],poss[MAXN],pd[MAXN];
vector<node> q[MAXN];
queue<int> wk;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>T;
for(int i=1;i<=m;i++){
int x,y,z;cin>>x>>y>>z;
q[x].push_back((node){y,z});
q[y].push_back((node){x,z});
}
for(int i=1;i<=n;i++){
mf[i]=ms[i]=2e14;
sort(q[i].begin(),q[i].end(),cmp);
}
for(int i=1;i<=T;i++){
int x;cin>>x;
flag[x]=1;
wk.push(x);
}
while(!wk.empty()){
int x=wk.front();
wk.pop();
if(flag[x]){
pd[x]=1;
lst=0;
for(int i=0;i<q[x].size();i++){
node tmp=q[x][i];
if(tmp.pos==lst||pd[tmp.pos]) continue;
lst=tmp.pos;
if(flag[tmp.pos]){
ans=min(ans,tmp.dis);
continue;
}
if(mf[tmp.pos]>tmp.dis){
ms[tmp.pos]=mf[tmp.pos];
mf[tmp.pos]=tmp.dis;
poss[tmp.pos]=posf[tmp.pos];
posf[tmp.pos]=x;
}
else if(ms[tmp.pos]>tmp.dis){
ms[tmp.pos]=tmp.dis;
poss[tmp.pos]=x;
}
wk.push(tmp.pos);
}
}
else{
if(pd[x]) continue;
pd[x]=1,lst=0;
for(int i=0;i<q[x].size();i++){
node tmp=q[x][i];
if(tmp.pos==lst||pd[tmp.pos]) continue;
lst=tmp.pos;
int lenf=mf[x]+tmp.dis;
int lens=ms[x]+tmp.dis;
if(posf[x]==posf[tmp.pos]){
if(mf[tmp.pos]<lenf) mf[tmp.pos]=lenf;
}
else{
if(lenf<mf[tmp.pos]){
ms[tmp.pos]=mf[tmp.pos];
mf[tmp.pos]=lenf;
poss[tmp.pos]=posf[tmp.pos];
posf[tmp.pos]=posf[x];
}
else if(lenf<ms[tmp.pos]){
ms[tmp.pos]=lenf;
poss[tmp.pos]=posf[x];
}
}
if(lens<ms[tmp.pos]&&poss[x]!=posf[tmp.pos]){
ms[tmp.pos]=lens;
poss[tmp.pos]=poss[x];
}
wk.push(tmp.pos);
}
}
}
for(int i=1;i<=n;i++){
if(!flag[i]) ans=min(ans,mf[i]+ms[i]);
}
cout<<ans;
return 0;
}
据说还有一种神奇方法,对于每一个关键点跑一遍dijsktra,可以证明找到的第一个关键点就是距离当前关键点最近的点,取最小值即可,不过没有尝试过;
T3 冒泡
冒泡排序有一个极其显然的性质,就是交换次数等同于序列的逆序对个数,这个也是非常容易考的;
30%
对于 \(30%\) 的部分分,可以直接暴力枚举每一个数,构造出序列求逆序对数累加即可;不过主播错误估计了时间复杂度认为这不可解,导致丢失了30分 (悲
40%
对于另外 \(10%\) 的 \(L=R\) 的情况,直接构造序列统计,肥肠煎蛋;
100%
直接引用zhangxy学长的题解

放上代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int T,pw[500005];
string l,r;
//int cnt[15],len,tot,sum,ans;
int getc(string s){
int x=s.size(),tot=0,sum=0,res=0,cnt[15]={0};
for(char ch:s){
int c=ch^48;
x--;
for(int i=0;i<c;i++){
if(x>=2){
(res+=x*(x-1)/2%mod*45%mod*pw[x-2])%=mod;
}
if(x>=1){
(res+=(sum+i)*x%mod*pw[x-1])%=mod;
}
(res+=(tot+cnt[i+1])*pw[x])%=mod;
}
(tot+=cnt[c+1])%=mod,(sum+=c)%=mod;
for(int i=0;i<=c;i++){
cnt[i]++;
}
// cout<<res<<" ";
}
// cout<<"\n";
return res;
}
int gets(string s){
int len=s.size(),tot=0,sum=0,ans=0;
int cnt[15]={0};
for(int k=0;k<s.size();k++){
int c=s[k]-'0';
for(int i=c+1;i<=9;i++) (ans+=cnt[i])%=mod;
cnt[c]++;
}
return ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
pw[0]=1;
for(int i=1;i<=500001;i++) pw[i]=pw[i-1]*10%mod;
while(T--){
cin>>l>>r;
// cout<<getc(r)<<" "<<getc(l)<<" "<<gets(r)<<"\n";
cout<<((getc(r)-getc(l)+gets(r)+mod)%mod)%mod<<"\n";
}
return 0;
}
T4 亲戚
依旧不会……
伟大的wyl曾说过,如果一道题目的名称是一个算法的话,那么这个题目的正解一定和这个算法无关
本文来自博客园,作者:zhangch_qwq,转载请注明原文链接:https://www.cnblogs.com/zhangchenhua-awa/p/19034284

浙公网安备 33010602011771号