传送门:CF
本来想写到D的,奈何D题是个比较烦的模拟题,所以就提前润了
A题:A. Yura’s New Name
简单的模拟题.发现 “^^” 我们是不需要考虑的,因为 “^” 要么被包含在"^“中,要么会被包含在” ^ _ ^ “中,所以只要考虑后者即可.
也就是对于每一个”_“,我们需要保证它的左右存在”^",实现的时候注意首尾即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
int T=read();
while(T--) {
string s;cin>>s;int ans=0;
if(s.find('_')==s.npos) {
if(s.length()==1) {
cout<<1<<endl;
continue;
}
}
if(s[0]=='_') ans++;
for(int i=1;i<s.length();i++) {
if(s[i]=='_') {
if(s[i-1]=='_') {
ans++;
}
}
}
if(s.back()=='_') ans++;
cout<<ans<<endl;
}
return 0;
}
B题:B. JoJo’s Incredible Adventures
刚开始想的是循环建图然后找最大子矩阵,但是想想比较难以实现,本题又是B题,应该没那么复杂,所以考虑找找规律.
首先如果全部都是1和0,我们可以直接特判出结果.
然后我们仔细观察一下样例:
0 1 1 1 1 0
0 0 1 1 1 1
1 0 0 1 1 1
1 1 0 0 1 1
1 1 1 0 0 1
1 1 1 1 0 0
我们会发现存在这样的一个结论,我们发现每一段连续的1在贡献最大矩阵的时候是相互独立.诶,这个怎么理解呢.想象一下,我们有两段1,其中被0隔开了,在我们的1往右循环的过程中,我们的这些0既隔开了左右两边又隔开了上下.然后我们的两段1就不可能在一起贡献出最大的子矩阵了.这个规律很重要,有了这个规律之后我们就可以独立考虑最长的那一段1即可(贪心的去想,显然最长的更容易产生更大的子矩阵!)
我们假设我们的连续的1的长度为n.不难发现:
n=1时,子矩阵大小为
1
∗
1
1*1
1∗1
n=2时,子矩阵大小为
1
∗
2
1*2
1∗2
n=3时,子矩阵大小为
2
∗
2
2*2
2∗2
n=4时,子矩阵大小为
2
∗
3
2*3
2∗3
等等,我们可以
O
(
1
)
O(1)
O(1)解决这个问题.
但是存在一个细节需要考虑,因为我们的序列是循环的,也就是头尾相接,所以我们在找最长的连续的1时需要考虑环的情况,这个也很好解决,复制原本的链接在后边即可(老生常谈的解决方案了)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
int T=read();
while(T--) {
string s;cin>>s;int ans=0;
if(s.find('_')==s.npos) {
if(s.length()==1) {
cout<<1<<endl;
continue;
}
}
if(s[0]=='_') ans++;
for(int i=1;i<s.length();i++) {
if(s[i]=='_') {
if(s[i-1]=='_') {
ans++;
}
}
}
if(s.back()=='_') ans++;
cout<<ans<<endl;
}
return 0;
}
C题:Constructive Problem
我个人认为这道题是一道答辩题
首先题意很好理解,思路也很好想到,但是实现一言难尽
考虑如何使
M
E
X
MEX
MEX加一,我是分类来考虑的:
1.首先如果初始的 M E X MEX MEX(下面的 M E X MEX MEX全部都指初始情况,不再特意说明)是0,那么我们必然是可以解决的,只要将所有值赋值为0即可
2.如果我们序列中不存在 M E X + 1 MEX+1 MEX+1,注意这个是需要分开来考虑的,因为如果想要 M E X + 1 MEX+1 MEX+1,那么我们必然是将一个数改为 M E X MEX MEX,然后迫使它+1,但是如果我们本来存在 M E X + 1 MEX+1 MEX+1,此时我们可能变成了 M E X + 2 MEX+2 MEX+2.假设我们不存在 M E X + 1 MEX+1 MEX+1的话,我们有两种解决方案,要么我们数列中小于 M E X MEX MEX的数字个数不止一个,我们将这个数改为 M E X MEX MEX即可;要么我们可以将大于 M E X MEX MEX的数字拿出一个改为 M E X MEX MEX即可
3.我们的序列中存在 M E X + 1 MEX+1 MEX+1,我们必须要想办法删除所有的 M E X + 1 MEX+1 MEX+1,但是同时我们又需要出现一个 M E X MEX MEX,并且只能操作一次.所以我们只能找到包含所有的 M E X + 1 MEX+1 MEX+1的区间的最左端及最右端,记为 L , R L,R L,R,然后将这些数字全部改为 M E X MEX MEX(只有这样我们才能产生 M E X MEX MEX!).但是我们这个区间不一定只包含 M E X MEX MEX,可能在删除 M E X + 1 MEX+1 MEX+1的时候使其他数字又不存在了,所以我们又需要重新判断一下
博主本题的代码写的十分的丑陋,而且常数极大,在CF的C++14编译器上甚至被卡常,使用C++20才AC,所以只提供参考,具体实现方法在上述讲述中已经十分清楚了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
map<int,int>mp,mp2;
int main() {
int T=read();
while(T--) {
int n=read();int maxx=-int_INF;
mp.clear();mp2.clear();
for(int i=1;i<=n;i++) {
a[i]=read();
mp[a[i]]++;
}
int num=-1;
for(int i=0;;i++) {
if(mp[i]==0) {
num=i;
break;
}
}
for(int i=1;i<=n;i++) {
if(i==n) {
mp2[a[i]]++;break;
}
if(a[i+1]==a[i]) {
mp2[a[i]]++;
while(a[i+1]==a[i]) i++;
}
else {
mp2[a[i]]++;
}
}
if(num==0) {
puts("Yes");
continue;
}
if(mp[num+1]) {
vector<int>v;
for(int i=1;i<=n;i++) {
if(a[i]==num+1) {
v.push_back(i);
}
}
for(int i=0;i<v.size();i++) {
if(i==v.size()-1) {
mp[num+1]--;
}
else {
for(int j=v[i];j<=v[i+1]-1;j++) {
mp[a[j]]--;
}
}
}
int cnt=0;int kkk=0;
for(int i=0;;i++) {
if(mp[i]==0) {
if(i==num+1) {
kkk=1;
break;
}
else {
if(cnt==0) {
cnt++;
}
else {
kkk=0;
break;
}
}
}
}
if(kkk==1) {
puts("Yes");
}
else {
puts("No");
}
continue;
}
int flag=0;
for(int i=0;i<num;i++) {
if(mp[i]!=1) {
flag=1;
break;
}
}
if(flag==1) {
puts("Yes");
continue;
}
for(int i=1;i<=n;i++) {
if(a[i]>num) {
flag=1;
break;
}
}
if(flag==1) {
puts("Yes");
}
else {
puts("No");
}
}
return 0;
}