514D (二分+区间最值)

来源:互联网 发布:黑人假发 知乎 编辑:程序博客网 时间:2024/06/18 10:52

题目传送

题目大意: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 __int64int 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;}

    

 
 
1

 

 

 

0 0
原创粉丝点击