514D (二分+区间最值)

题目传送

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

    

 
 
1

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值