cf E. George and Cards

时间:2023-03-08 21:47:36

http://codeforces.com/contest/387/problem/E

题意:给你n个数,然后在输入k个数,这k个数都在n个数中出现,进行每一次操作就是在n个数中选择长度为w的连续序列,然后删除这w个数中的最小的一个,然后你就会的到w个奖励,如何获得最多奖励?

思路:set+数状数组,数状数组用来记录在每一个连续的区间内数的个数,用来记录删除和添加数的个数,先对a数组中的数记录每一个数在序列中的位置,再对b数组进行标记,然后遍历1-n,被标记数,把它的位置放在set里面,没有被标记的,在set里面二分查找到大于等于它位置的数,可以知道下界和上界,就可以知道这次的w,就可以求出答案。

 #include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>
#define ll long long
#define maxn 1000010
using namespace std; int n,k;
int p[maxn];
int b[maxn];
int c[maxn];
int pos[maxn];
bool vis[maxn];
struct node
{
int x,id;
bool operator <(const node &a)const
{
return x<a.x;
}
} f[maxn]; int lowbit(int x)
{
return x&-x;
} void insert(int x,int d)
{
while(x<maxn)
{
c[x]+=d;
x+=lowbit(x);
}
} int Getsum(int x)
{
int ans=;
while(x>)
{
ans+=c[x];
x-=lowbit(x);
}
return ans;
} int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
set<int>q;
set<int>::iterator it;
for(int i=; i<=n; i++)
{
scanf("%d",&p[i]);
insert(i,);
pos[p[i]]=i;
}
for(int i=; i<=k; i++)
{
scanf("%d",&b[i]);
vis[b[i]]=true;
}
ll ans=;
q.insert(); q.insert(n+);
for(int i=; i<=n; i++)
{
if(vis[i])
{
q.insert(pos[i]);
}
else
{
it=q.lower_bound(pos[i]);
int r=*it-;
int l=*(--it);
ans+=Getsum(r)-Getsum(l);
insert(pos[i],-);
}
}
printf("%lld\n",ans);
}
return ;
}