Technocup 2020 - Elimination Round 3 D2. Optimal Subsequences (Hard Version) (树状数组+二分+思维)

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题意:给一个长度为n的序列,m次询问,问你原序列的总和最大且字典序最小的长度为k的子序列的第pos位元素是多少。
思路:一开始每个长度得最优序列其实是可以构造出来的,但是数组开不了那么大,而且也容易tle,所以一种思路不行换一种思路,我们可以将这m个询问进行排序,由于是离线操作,我们可以通过树状数组来快速构造满足条件的序列,这里简单说一下怎么的序列是最优的,就是尽可能地保留大的数,如果一个数不能全部删完,那么我们优先删除下标靠后的,所以我们排序的时候先按值从大到小排,当值相同时按下标从小到大排。至于第pos位的话用树状数组加二分来查。

#include <bits/stdc++.h>
using namespace std;
#define lowbit(i)  ((i)&(-i))
const int maxn=2e5+1;
int n,q,b[maxn],c[maxn],ans[maxn];
struct node{
	int num,id;
}a[maxn];
struct cxk{
	int k,pos,id;
}s[maxn];
bool cmp(const node &a,const node &b)
{
	return a.num==b.num?a.id<b.id:a.num>b.num;
}
bool cmp2(const cxk &x,const cxk &y)
{
	return x.k<y.k;
}
void update(int x)
{
	while(x<maxn) c[x]++,x+=lowbit(x);
}
int query(int x)
{
	int res=0;
	while(x>0) res+=c[x],x-=lowbit(x);
	return res;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i].num),b[i]=a[i].num,a[i].id=i;
	sort(a+1,a+1+n,cmp);
	scanf("%d",&q);
	for(int i=1;i<=q;++i)
	scanf("%d%d",&s[i].k,&s[i].pos),s[i].id=i;
	sort(s+1,s+1+q,cmp2);
	int k=1;
	for(int i=1;i<=q;++i)
	{
		while(k<=s[i].k) update(a[k].id),k++;
		int l=1,r=n;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(query(mid)>=s[i].pos) r=mid;
			else l=mid+1;
		}
		ans[s[i].id]=b[l];
	}
	for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
 } 
发布了144 篇原创文章 · 获赞 0 · 访问量 4958

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104435159