题目大意:n*m的矩阵,最多可进行k次操作,每次使得一列上的所有数值-1,若一行的数值全变为0,则该行被破坏。问最长可连续破坏多少行。输出此时对于每一列的操作数。
思路很直接:对于每一列,二分区间长度,枚举起点,求区间最大值。将每一列的区间最值相加,若不超过k,则该长度可行。
对于输出方案,可开设数组a[i]记录长度为i的起点,若最终长度为len,则再次求区间[a[len],a[len]+len-1]的最大值即可。
#include<bits/stdc++.h> using namespace std; #define LL __int64 int f[5][100005][20],ans[100005],k,n,m; void rmq(int p,int n) { for(int j=1;(1<<j)<=n;++j) for(int i=1;i+(1<<j)-1<=n;++i) f[p][i][j]=max(f[p][i][j-1],f[p][i+(1<<(j-1))][j-1]); } int query(int p,int l,int r) { int k=(int)(log(1.0*(r-l+1))/log(2.0)); return max(f[p][l][k],f[p][r-(1<<k)+1][k]); } bool judge(int len) { int i,j,s; for(i=1;i+len-1<=n;++i) { s=0; for(j=0;j<m;++j) s+=query(j,i,i+len-1); if(s<=k) { ans[len]=i; return 1; } } return 0; } int main() { int i,j; scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;++i) for(j=0;j<m;++j) scanf("%d",&f[j][i][0]); for(i=0;i<m;++i) rmq(i,n); int len=0,l=1,r=n; while(l<=r) { int mid=(l+r)>>1; if(judge(mid)) { l=mid+1; len=mid; } else r=mid-1; } for(i=0;i<m-1;++i) printf("%d ",query(i,ans[len],ans[len]+len-1)); printf("%d\n",query(i,ans[len],ans[len]+len-1)); return 0; }