1🐋🐋🐋MC0204世界警察(黄金;双指针)
时间限制:4秒
占用内存:1024M
🐟题目描述
世界警察小码哥来谈判了,恐怖分子在银行挟持了 n 个人质,每个人质都所属一个国家,第 i 个人质所属的国家为 ci,人质排成了一排,位置都是固定的。经过商讨,恐怖分子允许小码哥可以带走任意一段连续区间内的人质。但是上级要求小码哥,最好每个国家的人质都带回来一个,不希望人质中有重复的国家。请问小码哥最多可以带出来多少人质。
🐟输入输出格式
输入格式:
第一行一个正整数 n,表示共有 n 个人质;
第二行共有 n 个正整数,第 i 个正整数表示第 i 个人质的所属国家 ci。
输出格式:
一个整数表示小码哥最多可以带出来的人质数
🐟样例
🐚样例
输入:
5
1 1 2 3 4
输出:
4
🐚备注
其中:1≤n≤10^6;0≤ci≤10^9。
🐟题目思路
这道题目是典型的双指针区间问题,关键点在于如何发现重复数字以及如何处理重复数字:
- 使用map的find功能查找该数字是否已存在;
- 如果存在,那么结果区间只有两种情况:包含上一个和包含这一个。现在的情况就是包括上一个的情况,那么就直接判断长度;包含这一个(也就是现在右指针遇到的这个)的情况,那么该段的初始位置就是上一个该数字的下一个位置(+1)
⭐这里注意一点,也就是4的制胜点:在包含这一个的情况下,要额外判断这一个数是否已被放入到map当中。
🐟代码
cpp
#include<bits/stdc++.h>
using namespace std;
int main( )
{
long long n;
cin>>n;
if(n==1) cout<<1<<endl;
long long l=0,r=0;
long long c;
vector<long long> a;
map<long long,long long> cur;
int flag=0;
for(long long i=0;i<n;i++)
{
cin>>c;
a.push_back(c);
if(c!=a[0]) flag=1;
}
if(flag==0) cout<<1<<endl;
cur.insert({a[0],0});
long long ans=1;
for(long long i=1;i<n;i++)
{
auto it=cur.find(a[i]);
if(it==cur.end())
{
r++;
cur.insert({a[i],i});
}
else
{
ans=max(ans,r-l+1);
for(long long j=l;j<=it->second;j++) cur.erase(a[j]);
l=it->second+1;
if(cur.find(a[i])==cur.end()) cur.insert({a[i],i});//4的制胜点
r++;
}
}
ans=max(ans,r-l+1);
cout<<ans<<endl;
return 0;
}
2🐋🐋🐋MC0206小码哥的英语(白银;普通循环)
时间限制:1秒
占用内存:256M
🐟题目描述
小码哥在做英语单选题的时候突然想到了一个很有意思的问题:单选题的答案都是A或者B,那么很多道题目的答案组成的就是一个A和B组成的字符串。如果两个相邻的题目的答案是相同的,小码哥就可以修改这两个题目的答案,改成都是A、都是B或者一个是A另外一个是B,小码哥把这个定义为一次操作。那么对于任意一个答案字符串,最少需要多少次操作,才能使得它满足:任意相邻的题目的答案都不同。
🐟输入输出格式
输入格式:
第一行包含一个数字 n (1≤n≤1000),表示字符串的个数;
后面的 n 行,每一行表示一个长度为L(1≤L≤10000)的,由字符A和B随机组成的字符串。
输出格式:
输出有多行,每一行表示对应字符串需要的最少的操作次数T(0≤T≤10000)。
🐟样例
输入:
2
AAABAB
AABBBAB
输出:
1
2
🐟题目思路
乍一看这道题目,我以为是模拟过程,遇到两个相同的或三个相同的记为1,但是发现不对,一个点也过不了。后来受到forward---backward思想的启发,既然最后达到的状态是相邻两个字母不同,那么就只有两种可能:ABABAB和BABABA。基于此,我们只需要遍历字符串,然后和标准答案对比即可知道要做几次操作了。
🐟代码
cpp
#include<bits/stdc++.h>
using namespace std;
int main( )
{
int n;
cin>>n;
string s;
int ans1,ans2;
for(int k=0;k<n;k++)
{
cin>>s;
ans1=0;
ans2=0;
for(int i=0;i<s.size();i++)
{
if(i%2==0&&s[i]!='A') ans1++;
if(i%2==1&&s[i]!='B') ans1++;
if(i%2==0&&s[i]!='B') ans2++;
if(i%2==1&&s[i]!='A') ans2++;
}
cout<<min(ans1,ans2)<<endl;
}
return 0;
}
3🐋🐋🐋MC0207中转站(黄金;简易版DFS)
时间限制:1秒
占用内存:256M
🐟题目描述
物流业为了降低物流成本,提高物流效率,运输过程中通常不会由始发地直达目的地,而是经由多个中转站中转,最终到达目的地。最常见的便是快递业,由于中转站有很多,要想将所有中转站两两互通代价过高,因此每个中转站只会与个别中转站单向或双向连通。
在接受订单时,为了判断该物件能否送达,会先查询本站是否能直接送达目的地站点;若不能,则递归查询本站可达中转站,以及中转站的中转站能否送达,直至找出目的地或找遍全部中转站。
🐟输入输出格式
输入格式:
第一行输入两个正整数 n,m,n 是整个物流网所有中转站的数目,小码哥所在的站点是 1 号,目的地的站点是 n 号;
接下来的 m 行,每行输入两个正整数 x,y,代表中转站 x 可以送往中转站 y。
输出格式:
如果物件能够送达,输出”Yes”,否则输出”No”。
🐟样例
🐚样例1
输入:
5 5
1 3
2 3
3 4
2 4
4 5
输出:
Yes
🐚样例2
输入:
4 3
1 2
2 3
4 1
输出:
No
🐚备注
其中:1<n≤500,1<m≤20000,1≤x,y≤n
🐟题目思路
题目很明显是想让我们用图遍历,这里主要是DFS深度优先遍历。但是DFS挺麻烦的(主要是我不太会😂),所以考虑一些更简单的方法。一个思路是,模拟DFS的过程,但是不使用迭代的方法:用数组p记录某一个点能否到达,也就是说,输入cur和next,如果p[cur]==1,那么意味着之前有路径能到达cur,那么自然p[next]就可以置为1了,意味着有路径可以到达next这一节点。
🐟代码
cpp
#include<bits/stdc++.h>
using namespace std;
int main( )
{
int n,m;
cin>>n>>m;
vector<int> p(n+1,0);
int cur,next;
cin>>cur>>next;
p[cur]=1;
p[next]=1;
m--;
for(int i=0;i<m;i++)
{
cin>>cur>>next;
if(p[cur]==1) p[next]=1;
}
if(p[n]==1) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
4🐋🐋🐋MC0210安全验证(钻石;KMP算法)
时间限制:1秒
占用内存:256M
🐟题目描述
小码哥是一名密码学专家,一天他的朋友拜托他设计一个简单的标识验证程序,用于服务器安全验证。
小码哥答应了朋友的请求,设计了一个简单的标识验证方法。服务器会自带一个安全标识串 S,每隔一段时间会自动更新,客户端的每次请求都会先收到服务器的标识串,然后在下一次更新前需要找出 S 中的一个真子串 T,满足既是 S 的前后缀,又在 S 中出现至少一次的最长串,找到后才能正常与服务器交互。
小码哥虽然精通密码学,但对开发一窍不通,于是找到了你,希望你能协助他完成程序开发环节。
🐟输入输出格式
输入格式:
一个字符串 SS,全部是小写字母。
输出格式:
满足条件的最长真子串 TT,如果没有就输出”No”。
🐟样例
🐚样例1
输入:
fixprefixsuffix
输出:
fix
🐚样例2
输入:
abcdabc
输出:
No
🐚备注
其中:3≤∣S∣≤10^6
🐟题目思路
题目给了比较明显的提示:最长前后缀。具体前后缀的介绍可以看我之前的一篇leetcode的内容:
⭐每天一道leetcode:28.找出字符串中第一个匹配项的下标(简单;暴力解;KMP算法,有难度)-CSDN博客
这道题目的思路就是:在KMP算法计算出前缀数组的基础上,判断除去前后缀部分的字符串是否仍包含这样至少一个前缀,如果是的那么输出这个前缀ans,否则输出No。这里判断是否包含,我是用了暴力求解的方法,也就是使用substr函数截取以i位置为起点的与ans等长度的子字符串,然后判断是否与ans相等。
🐟代码
cpp
#include<bits/stdc++.h>
using namespace std;
int main( )
{
string s;
cin>>s;
vector<int> pi(s.size());
for(int i=1,j=0;i<s.size();i++) //求s的前缀函数
{
while(j>0&&s[i]!=s[j])
{
j=pi[j-1];
}
if(s[i]==s[j]) j++;
pi[i]=j;
}
string ans;
//判断除了前后缀,中间部分是否还至少有一个前缀
if(pi[s.size()-1]==0) cout<<"No"<<endl;
else
{
for(int i=0;i<pi[s.size()-1];i++) ans+=s[i];
if(s.size()-2*pi[s.size()-1]<pi[s.size()-1]) cout<<"No"<<endl;
else
{
for(int i=pi[s.size()-1]-1;i<s.size()-pi[s.size()-1];i++)
{
if(s.substr(i,ans.size())==ans)
{
cout<<ans<<endl;
return 0;//这里要用return,如果用break,后边那个No也会被输出出来;或者可以用break加一个flag标记一下
}
}
cout<<"No"<<endl;
}
}
return 0;
}
⭐点赞收藏不迷路~