2025 SMU WINTER 1th
前言
内含2025 smu winter round1,2,3,4 + 总结
比赛
SMU Winter 2025 Round 1
https://vjudge.net/contest/686497
02 Yes...中找子字符串
这个题目是先把后面的题目写了才反过来写这个的,因为最开始做交了一发然后wa了(T T)
第一次交他反馈给我的是wa2,我猜测是初始化的s0的Yes长度可能不太够,因为题目输入的最大字符串长度是50,我就整好输出的是17个
又多加了几个Yes,ac了(Y ^ _ ^ Y)
(贴上主体代码)
哦对,我这回用上了字符串里面的find函数,感觉很好用哇咔咔s0.find()!=string::npos
CLICK(Y ^ _ ^ Y)
void solve()
{
ll t;cin>>t;
string s0="YesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYesYes";
while(t--)
{
string s;cin>>s;
if(s0.find(s)!=string::npos)
{
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
}
后面有个学长发了他的解题思路捏
这样就不用管原字符串的“任意”长度了
CLICK(Y ^ _ ^ Y)
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t;cin>>t;
char nxt[300]{};
nxt['Y']='e',nxt['e']='s',nxt['s']='Y';
while(t--)
{
string s;cin>>s;
s+=nxt[s.back()];
int mark=1;
for(int i=0;i+1<s.size()&&mark;++i)
{
if(!nxt[s[i]]||nxt[s[i]]!=s[i+1]) mark=0;
}
if(mark) cout<<"Yes\n";
else cout<<"No\n";
}
}
04 丢失的序列
这道题比赛的时候没ac,〒▽〒
我后面发现我的思路一直是执着于一个一个去遍历,去构造满足条件的序列,在判断yes or no,其实只用判断是否能就行了,不用一个一个详细的构造
之前有回也是这样T_T
CLICK(Y ^ _ ^ Y)
void solve()
{
int m,s;cin>>m>>s;
int a[m+1]={0};
int ans=0;
for(int i=1;i<=m;++i)
{
cin>>a[i];
}
sort(a+1,a+1+m);
int cnt[a[m]+1]={0};
for(int i=0;i<=m;++i)
{
cnt[a[i]]++;
}
for(int i=1;i<=a[m];++i)
{
if(cnt[i]==0)
{
ans+=i;
}
}
if(ans>s)
{
cout<<"No\n";
return;
}else{
s-=ans;
int temp=a[m]+1;
while(s>0)
{
s-=temp;
temp++;
}
if(s==0)
{
cout<<"Yes\n";
return;
}else{
cout<<"No\n";
return;
}
}
}
05 除自己之外与最大者的差值
在第一次遍历的时候就把最大值,和第二大的值给找出来,因为后面判断有两种情况——判断元素是最大值or不是最大值
还有就是对我自己而言,最大值和第二大值的判断还是得注意
CLICK ^ _ ^
if(maxx1<a[i])
{
maxx2=maxx1;
maxx1=a[i];
}else if(a[i]>maxx2)
{
maxx2=a[i];
}
06 最小调温度次数
比赛的时候看这道题晕头转向的,赛后听讲解知道原来是这么想的
要分几种情况
- 首先特判:看a是否直接等于b
- 然后看a-x,a+x,b-x,b+x是否在l和r的范围里面
- 如果在,再计算a和b的距离
- 距离>=s ---> 一次 (结合题意)
dis>0 & dis<0
点击查看代码
void solve()
{
ll l,r,x;cin>>l>>r>>x;
ll a,b;cin>>a>>b;
if(a==b)
{
cout<<"0"<<endl;
return;
}
int x1=b-x;int x2=b+x;
int ck1=0,ck2=0;
if(x1<l) ck1++;
if(x2>r) ck2++;
if(ck1&&ck2){
cout<<"-1"<<'\n';
return;
}
int y1=a-x;int y2=a+x;
int ck3=0,ck4=0;
if(y1<l) ck3++;
if(y2>r) ck4++;
if(ck3&&ck4)
{
cout<<"-1"<<endl;
return ;
}
int dis=a-b;
if(fabs(dis)>=x)
{
cout<<"1"<<endl;
return ;
}
if(dis>0)
{
if(ck1==0)
{
cout<<"2"<<endl;
return ;
}
if(ck2==0)
{
if(ck4==0) //这里要注意ck3和ck4的判断顺序
{
cout<<"2"<<endl;
return;
}
if(ck3==0)
{
cout<<"3"<<endl;
return ;
}
}
}
if(dis<0)
{
if(ck2==0)
{
cout<<"2"<<endl;
return;
}
if(ck1==0)
{
if(ck3==0)
{
cout<<"2"<<endl;
return ;
}
if(ck4==0)
{
cout<<"3"<<endl;
return ;
}
}
}
}
07 两倍字符串构造回文
其实很好想的,直接把倒叙的字符串加到原来的字符串上就ok了
为什么交的第一次wa了呢〒▽〒因为lyq把'\0'也算进去了。。
08 三种山谷判断
- 升序
- 降序
- mid 这里使用缩点
缩点豪强哇〒▽〒
缩点
首先开一个动态数组
然后先把当前元素存入数组,判断当前元素是否等于下一个元素,
如果是,用while循环接着判断后面的也是不是等于,
如果等于就“跳过”
这样就能把一段线段缩成一个点
点击查看代码
#define int long long
void solve()
{
int n;cin>>n;
int a[n+10]={0};
for(int i=0;i<=n-1;++i)
{
cin>>a[i];
}
//up
bool up=true;
for(int i=0;i<=n-2;++i)
{
if(a[i]>a[i+1])
{
up=false;
break;
}
}
if(up)
{
cout<<"Yes\n";
return;
}
//down
bool down=true;
for(int i=0;i<=n-2;++i)
{
if(a[i]<a[i+1])
{
down=false;
break;
}
}
if(down)
{
cout<<"Yes\n";
return ;
}
//mid 缩点
vector<int>s;
for(int i=0;i<=n-2;++i)
{
s.push_back(a[i]);
if(a[i]==a[i+1])
{
int j=i+2;
while(a[j]==a[i] && j<=n-1)
{
j++;
}
i=j-1;
}
}
if(a[n-1]!=a[n-2])
{
s.push_back(a[n-1]);
}
n=s.size();
int cnt=0;
if(s[1]>s[0]) cnt++;
if(s[n-2]>s[n-1]) cnt++;
for(int i=1;i<=n-2;++i)
{
if(s[i]<s[i-1] &&s[i]<s[i+1])
{
cnt++;
}
}
if(cnt==1){
cout<<"Yes\n";
return;
}else{
cout<<"No\n";
return;
}
}
09 最大逆序数对
题目有说明最多一次操作
所以就有三种情况,存入三个数组之后,按三种情况依次遍历即可
但是要注意b数组和c数组分别要进行的操作的处理(倒序即可)
最后比较三个操作的最大值
点击查看代码
void solve()
{
int n;cin>>n;
int a[n+10]; //不变
int b[n+10]; //1变0
int c[n+10]; //0变1
for(int i=1;i<=n;++i)
{
int x;cin>>x;
a[i]=x;
b[i]=x;
c[i]=x;
}
int suma=0;
int cnta=0;
for(int i=n;i>=1;--i) //从n到1
{
if(a[i]==0)
{
cnta++;
}else{
suma+=cnta;
}
}
int sumb=0;
int cntb=0;
for(int i=n;i>=1;--i)
{
if(b[i]==1)
{
b[i]=0;
break;
}
}
for(int i=n;i>=1;--i)
{
if(b[i]==0)
{
cntb++;
}else{
sumb+=cntb;
}
}
int sumc=0;
int cntc=0;
for(int i=1;i<=n;++i)
{
if(c[i]==0)
{
c[i]=1;
break;
}
}
for(int i=n;i>=1;--i)
{
if(c[i]==0)
{
cntc++;
}else{
sumc+=cntc;
}
}
int maxx=max(max(suma,sumb),sumc);
cout<<maxx<<'\n';
}
12 XOR = Average
如果n是奇数,那么可以构造全为1的数列
如果n为偶数,要使得

要使等式成立,那么则数列的和要是n的倍数,假使为2 2 2 2,其实就相当于1 1 1 1了,异或答案为0,等式不成立,但是如果修改成2 2 1 3,则成立,左边异或为2(1和3异或结果是2)
点击查看代码
void solve()
{
int n;cin>>n;
if(n%2==1)
{
while(n--)
{
cout<<"1 ";
}
cout<<'\n';
}else{
cout<<"1 3 ";
n-=2;
while(n--)
{
cout<<"2 ";
}
cout<<'\n';
}
}
SMU Winter 2025 Round 2
https://vjudge.net/contest/687074#overview
这回时间还是很紧张的,两个小时。lyq还是体会到了不到最后不能放弃哈。我做完b题之后其实是把c题跳了的,感觉d题好像能写出来
然后就在那吭哧敲半天,最后发现方法给用错了。。。
实在不想用两题收尾,最后十六分钟开始重新看c题,把c写出来了(T _ T)
01 字符串数据比较
题意就是字符串前三个和后三个比,看是否相同
还有要注意的是输入数据是挨在一起的,如果int的话,会出现错误,我觉得应该是int字节数和char字节数的差异导致的
(lyq开的是数组)
02 最少糖果数量
看清题目哇!lyq以为可以重新分配每个盒子里面的糖果数量。。找到输入数据中的minn,然后sum-minn*n就得
03 最小差异字符串对
最开始阻碍我的是如何在输入的字符串中找到最小对
后面发现两层for循环嵌套就行了,( •̀ ω •́ )y
CLICK(❁´◡`❁)
int cmp(string s1,string s2,int m)
{
int ans=0;
for(int i=0;i<=m;++i)
{
if(s1[i]!='\0'&&s2[i]!='\0')
{
int temp=abs(s2[i]-s1[i]);
ans+=temp;
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int t;cin>>t;
while(t--)
{
string s[55];
int n,m;cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>s[i];
}
int minn=INT_MAX;
for(int i=1;i<n;++i)
{
for(int j=i+1;j<=n;++j)
{
int sum=cmp(s[i],s[j],m);
minn=min(sum,minn);
}
}
cout<<minn<<endl;;
}
return 0;
}
04 主教攻击最大和
稀里糊涂写半天,,,
后面听别人的思路,lyq你还是多学学点吧〒▽〒
用while+坐标移动来解决对角线
CLICK(❁´◡`❁)
void solve()
{
int n,m;cin>>n>>m;
int a[210][210];
int g[210][210];
int maxx=-1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
a[i][j]=0;
g[i][j]=0;
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int u=i,v=j;
while(u!=1&&v!=1)
{
u--;
v--;
}
while(u!=n&&v!=m)
{
g[i][j]+=a[u][v];
u++;
v++;
}
g[i][j]+=a[u][v];
u=i,v=j;
while(u!=1&&v!=m)
{
u--;
v++;
}
while(u!=n&&v!=1)
{
g[i][j]+=a[u][v];
u++;
v--;
}
g[i][j]+=a[u][v];
g[i][j]-=a[i][j];
if(g[i][j]>=maxx)
{
maxx=g[i][j];
}
}
}
cout<<maxx<<endl;
}
05 最少吃糖数量
前缀和+贪心+二分
点击查看代码
void solve()
{
int n,q;cin>>n>>q;
int a[n+10];
int sum[n+10];
for(int i=1;i<=n;++i)
{
cin>>a[i];
}
sort(a+1,a+1+n,greater<>());
sum[0]=0;
for(int i=1;i<=n;++i)
{
sum[i]=sum[i-1]+a[i];
}
while(q--)
{
int x;cin>>x;
int l=1;
int r=n;
int ans=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(sum[mid]>=x)
{
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
if(ans>=1&&ans<=n)
{
cout<<ans<<'\n';
// return;
}else{
cout<<"-1\n";
// return;
}
}
}
03 SMU Winter 2025 Round 3
https://vjudge.net/contest/687465#overview
01 睡觉时间
跨天的问题,通常都让lyq头疼一会
但这次感觉 化成分钟 这种方法能迁移到各个跨天的问题(?)
但是比赛的时候交的不知为什么就t掉了,,,后面改了点,莫名其妙又过了。。。
02 不同数字的序列
因为只能从数列的左边删除元素,所以在最后一个重复元素之前的元素都要去掉
所以我们不妨倒序,然后如果遇到了第一个重复元素,就break掉,没遇到就把当前元素存到数组里面
03 s的不同组成数字
贪心的运用
每次都从目前最大的的看,如果s>=i,那么就减去,并且纳入数组
点击查看代码
void solve()
{
int s;cin>>s;
vector<int>a(10);
for(int i=9;i>=1;--i)
{
if(s>=i)
{
a.push_back(i);
s-=i;
}
}
sort(a.begin(),a.end());
for(auto t:a)
{
if(t!=0)
cout<<t;
}
cout<<'\n';
}
04 最低的第一名
在纸张推算几次,会发现三种情况,%n得0,1,2
点击查看代码
void solve(){
int n;cin>>n;
int ave=n/3;
if(n%3==0)
{
cout<<ave<<" "<<ave+1<<" "<<ave-1<<'\n';
return;
}
if(n%3==1)
{
if(ave>2)
cout<<ave+1<<" "<<ave+2<<" "<<ave-2<<'\n';
else
cout<<ave<<" "<<ave+2<<" "<<ave-1<<'\n';
return ;
}
if(n%3==2)
{
cout<<ave+1<<" "<<ave+2<<" "<<ave-1<<'\n';
return;
}
}
05 n次操作后数组是否相同
找到两个数组差最大的,然后让每个元素-=maxx,
如果有负数,那么就再复制为0
如果最后处理后的数组和目标数组一样那么就ok
点击查看代码
#define int long long
void solve()
{
int n;cin>>n;
int a[n+10];
int b[n+10];
int d[n+10];
for(int i=0;i<n;++i)
{
cin>>a[i];
}
for(int i=0;i<n;++i)
{
cin>>b[i];
}
int maxx=-1;
for(int i=0;i<n;++i)
{
if(a[i]-b[i]>=0)
{
d[i]=a[i]-b[i];
maxx=max(d[i],maxx);
}
else{
cout<<"No\n";
return;
}
}
bool ok=true;
for(int i=0;i<n;++i)
{
a[i]-=maxx;
if(a[i]<0)
{
a[i]=0;
}
if(a[i]==b[i])
{
ok=1;
}else{
ok=false;
cout<<"No\n";
return;
}
}
if(ok==true)
cout<<"Yes"<<"\n";
}
07 黑白方格
这个和学姐当时上课给我们讲的前缀和的那个修路灯问题好像好像
所以就用前缀和做了
点击查看代码
#define int long long
void solve()
{
int n,k;cin>>n>>k;
int w[n+10]={0};
int qz[n+10]={0};
for(int i=1;i<=n;++i)
{
char x;cin>>x;
if(x=='W')
{
w[i]=true;
}
}
for(int i=1;i<=n;++i)
{
qz[i]=qz[i-1];
if(w[i])
{
qz[i]++;
}
}
int minn=INT_MAX;
for(int i=k;i<=n;++i)
{
minn=min(qz[i]-qz[i-k],minn);
}
cout<<minn<<endl;
}
08 abc非递减顺序

画相同颜色的下划线的元素可以互换顺序
分为集团来看,要是达到非递减顺序(也就是前一个元素大于等于后一个元素。依次递减是指前一个元素大于后一个元素),也就是要前一个集团的最大值小于等于后一个集团的最小值
点击查看代码
#define int long long
void solve()
{
int n;cin>>n;
int a[n+10];
for(int i=1;i<=n;++i)
{
cin>>a[i];
}
bool ok=false;
if(n==1)
{
cout<<"Yes\n";
return;
}
if(n==2)
{
cout<<"Yes\n";
return;
}
if(n%2)
{
int t=a[1];
for(int i=2;i<=n;i+=2)
{
if(min(a[i],a[i+1])>=t)
{
ok=true;
}else{
ok=false;
cout<<"No\n";
return;
}
t=max(a[i],a[i+1]);
}
if(ok)
{
cout<<"Yes\n";
return;
}
}
if(n%2==0)
{
int t=max(a[1],a[2]);
for(int i=3;i<=n;i+=2)
{
if(min(a[i],a[i+1])>=t)
{
ok=true;
}else{
ok=false;
cout<<"No\n";
return;
}
t=max(a[i],a[i+1]);
}
if(ok)
{
cout<<"Yes\n";
return;
}
}
}
SMU Winter 2025 Round 4
https://vjudge.net/contest/687995
05 区间求和
不能暴力解,会t
开个vis记录时间,如果vis[i]==dq(时间相同(不依赖于tot))就直接在原数组上加减
否则就算int temp=x-tot,然后让sum+=temp
点击查看代码
void solve()
{
ll n,q;cin>>n>>q;
ll a[n+10];
ll sum=0;
for(ll i=1;i<=n;++i)
{
cin>>a[i];
sum+=a[i];
}
ll vis[n+10]={0};
ll tot=-1;
ll dq=0;
while(q--)
{
ll t;cin>>t;
if(t==1)
{
ll i,x;cin>>i>>x;
if(vis[i]==dq)
{
ll temp=x-a[i];
a[i]=x;
sum+=temp;
}
else{
ll temp=x-tot;
sum+=temp;
a[i]=x;
vis[i]=dq;
}
cout<<sum<<'\n';
}else{
ll x;cin>>x;
tot=x;
sum=n*x;
dq++;
cout<<sum<<'\n';
}
}
}
06 攻击棋盘
因为棋盘的一条边就有1e5的数据,所以不能存二维数组
开两个set,存储安全的,没有被攻击到的行和列
点击查看代码
#define int long long
void solve()
{
int n,q;cin>>n>>q;
set<int>h,l;
vector<int>sumh(n+1),suml(n+1); //行or列被攻击的次数
for(int i=1;i<=n+2;++i)
{
h.insert(i); //没被攻击的行
l.insert(i); //没被攻击的列
}
while(q--)
{
int op;cin>>op;
if(op==1)
{
int x,y;cin>>x>>y;
h.erase(x);
l.erase(y);
sumh[x]++;
suml[y]++;
}
else if(op==2)
{
int x,y;cin>>x>>y;
sumh[x]--;
suml[y]--;
if(sumh[x]==0)
{
h.insert(x);
}
if(suml[y]==0)
{
l.insert(y);
}
}
else
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
int temp1=*h.lower_bound(x1);
int temp2=*l.lower_bound(y1);
if(temp1>x2||temp2>y2)
{
cout<<"Yes\n";
}else{
cout<<"No\n";
}
}
}
}
总结
这一周以比赛+补题为主。(但是还没补完哈〒▽〒)通过这一周的练习,我能感受到自己面对问题的思考能力和代码能力有在提升(❁´◡`❁)思维也变好了点。
同时我还是发现自己连续wa之后会急躁,maybe过一会在看思路能捋清~(详见r5的g题〒▽〒
还有就是算法的运用还是浮在浅浅的一层。还是要多练练哇(●'◡'●)
下周要学习下线段树,两次遇见它了,还有要写题单里的题目。

浙公网安备 33010602011771号