C

来源:互联网 发布:python 爬虫库推荐 编辑:程序博客网 时间:2024/06/06 00:39

题面:

D. R2D2 and Droid Army
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

An army of n droids is lined up in one row. Each droid is described by m integers a1, a2, ..., am, where ai is the number of details of the i-th type in this droid's mechanism. R2-D2 wants to destroy the sequence of consecutive droids of maximum length. He has m weapons, the i-th weapon can affect all the droids in the army by destroying one detail of the i-th type (if the droid doesn't have details of this type, nothing happens to it).

A droid is considered to be destroyed when all of its details are destroyed. R2-D2 can make at most k shots. How many shots from the weapon of what type should R2-D2 make to destroy the sequence of consecutive droids of maximum length?

Input

The first line contains three integers n, m, k (1 ≤ n ≤ 1051 ≤ m ≤ 50 ≤ k ≤ 109) — the number of droids, the number of detail types and the number of available shots, respectively.

Next n lines follow describing the droids. Each line contains m integers a1, a2, ..., am (0 ≤ ai ≤ 108), where ai is the number of details of the i-th type for the respective robot.

Output

Print m space-separated integers, where the i-th number is the number of shots from the weapon of the i-th type that the robot should make to destroy the subsequence of consecutive droids of the maximum length.

If there are multiple optimal solutions, print any of them.

It is not necessary to make exactly k shots, the number of shots can be less.

Examples
Input
5 2 44 01 22 10 21 3
Output
2 2
Input
3 2 41 21 32 2
Output
1 3
Note

In the first test the second, third and fourth droids will be destroyed.

In the second test the first and second droids will be destroyed.


题意:

     有n个有序排列的机器人,每个机器人有m项属性,每个机器人的每项属性并不统一。要消灭一个机器人,需要将他的每项属性值都减为1,现在有k次操作机会,每次操作可以将每个机器人的某项属性值都减1,问在不超过k次操作的情况下,如何分配每项属性减几次,可以使得最终消灭最多的连续机器人序列,输出分配攻击方案。

     注意:如果不能全部消灭,则每项输出0,因为要求消耗尽量少的操作数,达到杀死尽量多连续的机器人。

解题:

     RMQ,区间询问问题,可以做到O(nlogn)复杂度预处理,O(log n)复杂度询问,入门ST算法,可以看这篇博客,通过RMQ预处理好每项属性,区间最大值。

     随后询问时,只要查询出该区间每项属性的最大值,随后将这些最大值累加,即为消灭该区间全部机器人的最小操作次数。

     枚举左端点,二分右区间,若区间需要操作数大于k,则左移右区间,缩小区间长度,若小于等于k则,右移右区间,增大区间长度。在二分过程中更新区间最优值,同时还需记录此时的分配情况,若区间长度相等的情况下,还需保证操作数尽量小。

由此可以得出rmq算法还可以分别处理二维数组每个列的最大值,nlogn处理,logn查询

#include<iostream>#include<cstring>#include<stdio.h>const int maxn=100005;const int maxlog=20;using namespace std;int n,m,k;int a[100005][6];int path[6];//最终每条路的操作步骤int tmp[6];//中间每条路的操作步骤struct RMQ //用于求区间最值  (传入的是二维数组){    int d[maxn][6][maxlog];    void init(  int A[][6],int n) //被求最值的数组,数组的大小    {        //int n = A.size();        for(int i = 1; i <= n; i++)            for(int j=1;j<=m;j++)                d[i][j][0]=A[i][j];        for(int j = 1; (1<<j) <= n; j++)            for(int i = 1; i + (1<<j) - 1 <= n; i++)                for(int k=1;k<=m;k++)                    d[i][k][j] = max(d[i][k][j-1], d[i + (1<<(j-1))][k][j-1]);    }    int query(int L, int R)    {        int res=0;        if(R < L) swap(L, R);        //L++;        for(int i=1;i<=m;i++)        {            int k = 0;            while((1<<(k+1)) <= R-L+1) k++; // 如果2^(k+1)<=R-L+1,那么k还可以加1            tmp[i]=max(d[L][i][k], d[R-(1<<k)+1][i][k]);            res+=tmp[i];        }        return res;    }};void updata(){    for(int j=1;j<=m;j++)        path[j]=tmp[j];}RMQ rmq;int main(){    std::ios::sync_with_stdio(false);    while(cin>>n>>m>>k)    {        int ans=0,ansk=0x3f3f3f3f;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                cin>>a[i][j];            }        }        rmq.init( a,n );        for(int i=1;i<=n;i++)        {            int l=i,r=n;            while(l<=r)            {                int mid=(l+r)>>1;                int temp=rmq.query(i,mid);                if(temp <= k) //操作步骤少于k                {                    if(mid-i+1 > ans)//如果消灭机器人更多                    {                        ansk= temp;                        ans= mid-i+1;                        updata();                    }                    else if(mid-i+1 == ans)//如果消灭一样多                    {                        if(ansk>temp)//步骤更少                        {                            ansk=temp;                            updata();                        }                    }                    l=mid+1;                }                else                {                    r=mid-1;                    if(r-i+1 <ans)                        break;                }            }        }        printf("%d",path[1]);        for(int i=2;i<=m;i++)            printf(" %d",path[i]);        printf("\n");    }}





原创粉丝点击