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;
}