CodeForces - 514D-R2D2 and Droid Army(RMQ+二分)

题目链接:https://vjudge.net/problem/CodeForces-514D
题目大意:现在有一排机器人(n个),每个机器人有m个属性,你可以选择一种属性进行攻击,使所有机器人的这一属性都减1,当一个机器人所有属性都小于等于0时就视为被消灭了,现在你有k次攻击的机会,请问最多能够消灭连续的多少个机器人。

思路:因为是找的连续的最大长度,(连续的……),所以想要消灭某连续区间的机器人,每种属性攻击的次数都必须达到改区段的最大值。所以这里用RMQ维护一下区间最大值,然后枚举n个起点,二分找出k次攻击最远能够消灭到哪个位置。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define mid ((l + r)>>1)
#define chl root<<1
#define chr root<<1|1
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int manx=1e5+10;
int dp_max[manx][30][6],ans[7],len=0,mmax,m;
//dp_max[i][j][k]表示区间i~i+2^j-1的机器人第k种属性的最大值
void solve(int l,int r)
{
    int pos=l-1,sum,s=l;
    while(l<=r)
    {
        sum=0;
        int k=log2(mid-s+1);
        for(int i=1; i<=m; i++)
            sum+=max(dp_max[s][k][i],dp_max[mid-(1<<k)+1][k][i]);//查询
        if(sum<=mmax)
        {
            pos=mid;
            l=mid+1;
        }
        else
            r=mid-1;
    }
    if(pos!=s-1&&pos-s+1>len)
    {
        len=pos-s+1;
        int k=log2(len);
        for(int i=1; i<=m; i++)
            ans[i]=max(dp_max[s][k][i],dp_max[pos-(1<<k)+1][k][i]);
    }
}
int main()
{
    int n,temp;
    scanf("%d%d%d",&n,&m,&mmax);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            scanf("%d",&temp);
            dp_max[i][0][j]=temp;
        }
    }
    for(int j=1; j<=20; j++)
        for(int i=1; i+(1<<j)-1<=n; i++)
            for(int k=1; k<=m; k++)
                dp_max[i][j][k]=max(dp_max[i][j-1][k],dp_max[i+(1<<(j-1))][j-1][k]);
    for(int i=1; i<=n; i++)
        solve(i,n);//枚举起点
    for(int i=1; i<m; i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[m]);
    return 0;
}

你可能感兴趣的:(RMQ)