下笔春蚕食叶声。

题解 CF514D 【R2D2 and Droid Army】

题意

一共有N个人,每个人有M个属性值,
当一个人的所有属性值都小于等于0的时候,这个人就算被销毁了。

我们每次操作可以选一种属性值进行攻击,
使得所有人的这个属性的值都-1.

我们最多可以进行K次操作,
问我们最多可以干掉多少个连续的人。
问这种时候的具体操作(每一种属性用了多少次操作)

\(n \le 10^5 \ m \le 5 \ k \le 10^9\)

解法

二分干掉的连续人数

直接枚举每个长度为mid的区间

单调队列求区间最大值。

当所有 各属性的区间最大值 的和 \(sum \le K\) 时,存在方案干掉 \(mid\) 个人。

复杂度\(O(nlogn)\)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define rd(x) scanf("%d",&x);
typedef long long LL;
const int N=1e5+10,M=7;
int n,m,hd[M],tl[M],a[N][M],qaq[M],maxx[M];
LL k; 
int check(int len){
	rep(i,1,m) hd[i]=1,tl[i]=0;
	int q[M][N];memset(q,0,sizeof(q));
	int p[M][N];memset(p,0,sizeof(p));
	rep(i,1,n){
		LL sum=0;
		rep(j,1,m){
			while(hd[j]<=tl[j]&&q[j][tl[j]]<=a[i][j]) tl[j]--;
			q[j][++tl[j]]=a[i][j],p[j][tl[j]]=i;
			while(hd[j]<=tl[j]&&p[j][hd[j]]<=i-len) hd[j]++;
			if(i>=len) sum+=q[j][hd[j]],maxx[j]=q[j][hd[j]];
		}
		if(i>=len&&sum<=k){
			rep(j,1,m) qaq[j]=maxx[j];
			qaq[m]+=k-sum;return 1;
		} 
	}
	return 0;
}
int main(){
	rd(n);rd(m);scanf("%lld",&k);
	rep(i,1,n) rep(j,1,m)
		rd(a[i][j]);
	int l=0,r=n,ans;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid)) ans=mid,l=mid+1;
		else r=mid-1;
	}
	rep(i,1,m) printf("%d ",qaq[i]);
	return 0;
}

恭喜,一道水紫!

posted @ 2020-10-27 08:26  ACwisher  阅读(98)  评论(0编辑  收藏  举报