CF514D R2D2 and Droid Army(二分,ST表)

传送门

解题思路

直接二分能干掉的人数,然后check函数枚举所有区间,因为 m 很小,所以可以用 m 个ST表预处理每个区间对应每个属性的最大值。
一是需要注意二分的写法,而是注意check(0)时候的特判。

AC代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=2e5+5;
int n,m,k,a[maxn][6],d[6][maxn][20],ans[6],res[6];
int query(int id,int l,int r){
	int x=log2(r-l+1);
	return max(d[id][l][x],d[id][r-(1<<x)+1][x]);
}
bool check(int x){
	if(x==0) return 1;
	for(int i=1;i<=n-x+1;i++){
		int r=i+x-1,sum=0;
		for(int j=1;j<=m;j++){
			res[j]=query(j,i,r);
			sum+=res[j];
		}
		if(sum<=k){
			for(int j=1;j<=m;j++) ans[j]=res[j];
			return 1;
		}
	}
	return 0;
}
int main()
{
	n=read(),m=read(),k=read();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			d[j][i][0]=a[i][j]=read();
		}
	}
	for(int id=1;id<=m;id++){
		for(int len=1;(1<<len)<=n;len++){
			for(int i=1;i+(1<<len)-1<=n;i++){
				d[id][i][len]=max(d[id][i][len-1],d[id][i+(1<<(len-1))][len-1]);
			}
		}
	}
	int l=0,r=n;
	while(l<=r){
		int mid=(l+r)/2;
		if(check(mid)) l=mid+1;
		else r=mid-1;
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<' ';
    return 0;
}
posted @ 2024-02-29 10:31  尹昱钦  阅读(6)  评论(0编辑  收藏  举报