您的位置:首页 > 其它

JZOJ 5431. 【NOIP2017提高A组集训10.28】序列操作

2017-10-29 22:12 423 查看

Description

一开始有n个非负整数hi,接下来会进行m次操作,第i次操作给出一个数c[i],要求你选出c[i]个大于零的数并将它们减去1。

问最多可以进行多少轮操作后无法操作(即没有c[i]个大于零的数)

Input

第一行两个数表示n和m

第二行n个数描述h[i]

第三行m个数描述c[i]

Output

一行表示答案,即最多可以进行多少轮操作后无法操作

Sample Input

输入1:

3 5

1 2 5

1 2 3 2 1

输入2:

5 5

1 3 3 4 5

1 2 4 4 4

Sample Output

输出1:

3

输出2:

5

Data Constraint

对于10%的数据满足,1<=n,m<=5

对于另外20%的数据满足,1<=n<=8,1<=h[i]<=7

对于50%的数据满足,1<=n,m<=1000

对于80%的数据满足,1<=n,m<=100000

对于100%的数据满足,1<=n,m<=1000000

Solution

虽然数据有点大,还是决定线段树……

显然,选择的 c 个数一定选最大的那 c 个。

为了方便处理,先把数组排序,中途维护时也保证单调。

区间减,如果第 n−c+1 个数属于一段相同的数,就把相同的那段移到前面减(保证单调)。

时间复杂度 O(N log N) 。

Code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+2;
struct data
{
int mx,c;
}f[N<<2];
int ans;
int a
;
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline void modify(int v)
{
if(f[v].c)
{
int ls=v<<1,rs=ls|1;
f[ls].c+=f[v].c;
f[rs].c+=f[v].c;
f[ls].mx-=f[v].c;
f[rs].mx-=f[v].c;
f[v].c=0;
}
}
inline void make(int v,int l,int r)
{
if(l==r)
{
f[v].mx=a[l];
return;
}
int mid=(l+r)>>1;
make(v<<1,l,mid);
make(v<<1|1,mid+1,r);
f[v].mx=max(f[v<<1].mx,f[v<<1|1].mx);
}
inline void change(int v,int l,int r,int x,int y)
{
if(l==x && r==y)
{
f[v].c++;
f[v].mx--;
return;
}
modify(v);
int mid=(l+r)>>1;
if(y<=mid) change(v<<1,l,mid,x,y); else
if(x>mid) change(v<<1|1,mid+1,r,x,y); else
{
change(v<<1,l,mid,x,mid);
change(v<<1|1,mid+1,r,mid+1,y);
}
f[v].mx=max(f[v<<1].mx,f[v<<1|1].mx);
}
inline int findnum(int v,int l,int r,int x)
{
modify(v);
if(l==r) return f[v].mx;
int mid=(l+r)>>1;
int t=x<=mid?findnum(v<<1,l,mid,x):findnum(v<<1|1,mid+1,r,x);
f[v].mx=max(f[v<<1].mx,f[v<<1|1].mx);
return t;
}
inline int findpos(int v,int l,int r,int x)
{
modify(v);
if(l==r) return l;
int mid=(l+r)>>1;
int t=f[v<<1].mx>=x?findpos(v<<1,l,mid,x):findpos(v<<1|1,mid+1,r,x);
f[v].mx=max(f[v<<1].mx,f[v<<1|1].mx);
return t;
}
int main()
{
int n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+1+n);
make(1,1,n);
for(ans=0;ans<m;ans++)
{
int x=read(),t=findnum(1,1,n,n-x+1);
if(t<=0) break;
int pos2=findpos(1,1,n,t);
if(pos2<n-x+1)
{
int pos1=findpos(1,1,n,t+1);
if(pos1<=n && findnum(1,1,n,pos1)<=t) pos1++;
if(pos1<=n) change(1,1,n,pos1,n);
if(pos2+pos1-(n-x+1)-1<=n && pos2+pos1-(n-x+1)-1>=pos2) change(1,1,n,pos2,pos2+pos1-(n-x+1)-1);
}else change(1,1,n,n-x+1,n);
}
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: