Codeforces Round 887 (Div 2) C. Ntarsis' Set
题意是给你n个数,每次按照顺序删除位于a[i]位置的这n个数,问k次后最小的是多少
参考这位大佬的题解Codeforces Round 887 (Div 2)A~C - 知乎 (zhihu.com)
结合一个官方题解,进行一次操作后,由于前面删掉i个数,a[i]到a[i+1]间所有数的排名都要-=i,那么在a[i]到a[i+1]之间的数j,只要原先没有被删掉,一次操作后的j+i(如果k+i<a[i+1])一定就会取代上一次j的位置保留下来。换言之,此时位于空位j上的数值变成了j+i。当j+i>=a[i+1]时,说明[j+1,a[i+1]]之间的数都会被删掉,那么只能考虑大于a[i+1]的数值在一次操作后会来到空位j上。对于一个此时在a[i+1]后a[i+2]前的位置的一个数,一次操作后,它的位置-=(i+1),也就是说,当j+i>=a[i+1]时,此时在j+i+1位的数下一次会来到j这个位。也就是此时的更新操作是j=j+i+1。
所有综上,我们可以用一个变量now来表示此时的最小值,a[i]<now<a[i+1],当now+i<a[i+1]时,操作一次,此时的最小值变成now+i;直到now+i>=a[i+1]时,我们就让i增加,直到now+i<a[i+1],此时now再更新即可,now更新k次。
a[1]如果不是1的话无论k是多少最后答案都是1.
而当不操作的时候,最小值是1,now初值赋为1即可
自己代码遇到有几个语法上的坑,关闭流同步后尽量都用cout,少用puts scanf等,GCC17及以后就不要用register了
查看代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<iostream>
#define int long long
using namespace std;
int a[200005];
void solve()
{
int n,kk;
cin>>n>>kk;
for(int i=1;i<=n;i++)
cin>>a[i];
a[n+1]=1e18;
if(a[1]>1)
{
cout<<1<<endl;
return;
}
int now=1;
for(int i=2;i<=n+1;i++)
{
while(now+i-1<a[i])
{
now+=(i-1);
kk--;
if(kk==0)
break;
}
if(kk==0)break;
}
cout<<now<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
-------------------------------------------
个性签名:曾经的我们空有一颗望海的心,却从没为前往大海做过真正的努力
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!