Codeforces Round 887 (Div 2) C. Ntarsis' Set

发布时间 2023-07-24 11:42:31作者: qbning

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;
}