ARC-138解题报告
A. Larger Score
因为只需要增加而不限制增加量,所以找到一对前小后大的数对,设法将它们交换即可。具体来说,所以对于 lower_bound
找出),用
code:
#include<bits/stdc++.h>
using namespace std;
int a[400010];
int main() {
int n,k,ans=1e9;
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=k-1;i>0;i--)
a[i]=min(a[i],a[i+1]);
for(int i=k+1;i<=n;i++) {
int tmp=lower_bound(a+1,a+k+1,a[i])-a-1;
if(tmp==0) continue;
ans=min(ans,i-tmp);
}
if(ans==1e9) cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}
B. 01 Generation
由于只有前面加1反转和后面加0两种操作,所以考虑它们的分界线。
在前面的部分全部由添加1反转构成,所以一定是 010101...
这种形式,找出最长的满足要求的前缀,这就是第一部分。第一部分的0必须依次插入,可以发现,每插入一个0,第二部分就会受到影响,得到反转,所以当在第二部分中遇到连续的若干个0或连续的1的时候,它们一定(在最优解中)是同一块插入的。
而两块0、1的交界处必然进行了一次一操作(最优解中)。这样只需要比较操作一的次数(即最长01前缀的长度)和操作二的变化次数即可。如果操作一的次数小于第二部分的变化次数则不可行,反之可行。
这道题还有另一种思考方式,即倒序思考,将插入操作转化为删除。读者可自行考虑。
code:
#include<bits/stdc++.h>
using namespace std;
bool a[200010];
int main() {
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
if(a[1]==1) {
cout<<"No"<<endl;
return 0;
}
int now=1;
while(now<n&&a[now]!=a[now+1]) now++;
if(now==n) {
cout<<"Yes"<<endl;
return 0;
}
int ans=a[n];
for(int i=n-1;i>now;i--)
if(a[i]!=a[i+1]) ans++;
if(ans<=now) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
C. Rotate and Play Game
题目问最好情况,那么有一个很自然的猜测:最好情况一定可以取得最优解,即拿走大的那一半,留下小的那一半。这就要求我们在翻转之后,在任何一个前缀当中,小的数的个数
(数据 3 4 1 2
的图像)
那么,分成两半后互换就可以表示为,选一个点,以它为原点开始,再走回自己结束。这样结论就很显然了:选最低的点,以它为起点,坐标为0,那么之后无论怎么走也不会比它更低,满足要求。在此例子中,选择点 1 2 3 4
,满足要求。
(不得不说是一道非常巧妙的转化题)
code:
#include<bits/stdc++.h>
using namespace std;
int a[200010],b[200010];
int main() {
int n;
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
int fen=b[n/2];
long long mini=0,ans=0;
for(int i=n/2+1;i<=n;i++)
ans+=b[i];
for(int i=1;i<=n;i++)
if(a[i]<=fen) a[i]=1;
else a[i]=-1;
for(int i=2;i<=n;i++)
a[i]+=a[i-1];
for(int i=2;i<=n;i++)
if(a[i]<a[mini])
mini=i;
cout<<mini<<" "<<ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步