题目链接
题意:给一个长度为n的数列,每个数在1-n之间且各不相同。你可以从这个数列中删数:每次选一段区间,可以删除这个区间中最小的那个数,然后每次删除得到的分数是这个区间的长度。题目要你把原序列删成一个规定的长度为k的序列,并要得分最高。
思路:贪心的按数从小到大删,用set来维护b数组,同时二分查找大于当前数的位置,假设当前要删的数是3,那么r就是3的(最远的那个下标),l就是3的前面一个数2的下标+1,具体看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+1;
#define lowbit(i) (i)&(-i)
ll c[maxn],ans;
int n,k,t,a[maxn],vis[maxn],pos[maxn];
set<int>s;
void update(int x,int v)
{
while(x<maxn) c[x]+=v,x+=lowbit(x);
}
ll query(int x)
{
ll res=0;
while(x>0) res+=c[x],x-=lowbit(x);
return res;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
update(i,1);
pos[a[i]]=i;
}
for(int i=1;i<=k;++i) scanf("%d",&t),vis[t]=1;
s.insert(0);s.insert(n+1);
for(int i=1;i<=n;++i)
{
if(!vis[i])
{
auto it=s.upper_bound(pos[i]);
int r=(*it)-1,l=*(--it)+1;
ans+=query(r)-query(l-1);
update(pos[i],-1);
}
else s.insert(pos[i]);
}
printf("%lld\n",ans);
}