【打CF,学算法——四星级】CodeForces 514D R2D2 and Droid Army (RMQ+二分)

【CF简介】

提交链接:CF 514D


题面:

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 ≤ 105, 1 ≤ m ≤ 5, 0 ≤ 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 4
4 0
1 2
2 1
0 2
1 3
Output
2 2
Input
3 2 4
1 2
1 3
2 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则,右移右区间,增大区间长度。在二分过程中更新区间最优值,同时还需记录此时的分配情况,若区间长度相等的情况下,还需保证操作数尽量小。


代码:

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
#define LL long long
#define maxn 100010
#define sq(a)  1LL*(a)*(a)
#define mod 1000000007
using namespace std;
int arr[maxn][5],d[maxn][5][20],path[5],tmp[5];
int n,m,k;
void init()
{
  for(int i=0;i<n;i++)
	  for(int j=0;j<m;j++)
		  d[i][j][0]=arr[i][j];
  for(int j=1;(1<<j)<=n;j++)
	  for(int i=0;i+(1<<j)-1<n;i++)
		  for(int k=0;k<m;k++)
			  d[i][k][j]=max(d[i][k][j-1],d[i+(1<<(j-1))][k][j-1]);
}
int RMQ(int le,int ri)
{
	int k=0,res=0;
	for(int i=0;i<m;i++)
	{
		k=0;
		while((1<<(k+1))<=ri-le+1)
			k++;
		tmp[i]=max(d[le][i][k],d[ri-(1<<k)+1][i][k]);
		res+=tmp[i];
	}
	return res;
}
void update()
{				 
  for(int j=0;j<m;j++)
	path[j]=tmp[j];
}
int main()
{
	int le,ri,temp,ans=0,ansk=0x3f3f3f3f;
	bool flag=0;
	scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			scanf("%d",&arr[i][j]);
	init();

	for(int i=0;i<n;i++)
	{
      le=i;
      ri=n-1;
	  if(ri-le+1<ans)
		  break;
	  while(le<=ri)
	  {
         int mid=(le+ri)>>1;
		 temp=RMQ(i,mid);
		 if(temp<=k)
		 {
			 flag=1;
			 if(mid-i+1>ans)
			 {
				 ansk=temp;
				 ans=mid-i+1;
				 update();
			 }
			 else if(mid-i+1==ans)
			 {
				 if(ansk>temp)
				 {
					ansk=temp;
                    update();
				 }
			 }
			 le=mid+1;
		 }
		 else
		 {
			 ri=mid-1;
			 if(ri-i+1<ans)
				 break;
		 }
	  }
	}
	printf("%d",path[0]);
	for(int i=1;i<m;i++)
		printf(" %d",path[i]);
	printf("\n");
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值