Swordsman
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
问题描述
劳森是一个神奇的剑客,他有 k 种魔法属性 v1,v2,v3,... ,vķ。现在劳森面临着 n 个怪物, 怪物也有 k 种防御属性a1,a2,a3,... ,ak。如果v1≥ a1, 且 v2≥ a2, v3≥ a3, ... , vķ≥ ak,劳森就可以杀死怪物(每个怪物最多可以杀死一次)并从战斗中获得对应的属性值提升,这意味着 vj 将增加 bj,( j = 1 ,2 ,3 ,... ,ķ )。
现在我们想知道劳森最多可以杀死多少怪物以及劳森的魔法属性可以最大化到多少。
输入
有多个测试用例。第一行输入包含一个整数T,表明测试用例的数量。对于每个测试用例:
第一行有两个整数 n 和 k (1 ≤ n ≤ 1e5,1 ≤ k ≤ 5)。
第二行有 k 个非负整数(初始魔法属性) v1,v2,v3,... ,vķ。
接下来下 ñ 行, 对于每一行包含 2k 个非负整数(第 i 只怪物属性值,以及杀死他可获得的属性提升) a1,a2,a3,... ,ak 和 b1,b2,b3,... ,bk 保证所有输入整数都不超过1e9。
保证所有n的总和 ≤ 5e5。
输入数据非常大,因此建议使用快速IO(如`fread`)。
输出
对于每个测试用例:
第一行有一个整数,表示可以被劳森杀死的最大怪物数。
第二行有ķ 整数 v‘1,v‘2,v‘3,... ,v‘k 表示劳森最后属性值可提升到多少。
方法:
对于怪物的每种属性,我们进行从小到大排序,然后从小到大往前扫,如果某一个属性值可以被劳森压制,就对这只怪物进行标记,当这只怪物的标记数量达到 k 就表示它可以被杀死,就更新劳森的属性值,然后继续往后扫。例如题目样例:
怪物 | 3 | 1 | 4 | 2 |
---|---|---|---|---|
属性值 a1 | 0 | 5 | 6 | 24 |
怪物 | 4 | 2 | 3 | 1 |
---|---|---|---|---|
属性值 a2 | 0 | 1 | 4 | 5 |
怪物 | 4 | 3 | 2 | 1 |
---|---|---|---|---|
属性值 a3 | 1 | 1 | 1 | 2 |
对于怪物的三种属性值可排成这样,在最初劳森的属性值为 7 1 1 ,对于第一个属性,看第一张表劳森可以压制的怪物是表前三个,所以我们给表中前三只怪物(3、1、4)标记都加 1 , 第二张表可压制 4、2 标记加 1 。找第三张表的时候,显然劳森可以压制表中第一只怪( 4 ),而第4号怪的标记此时达到了 3 个,说明第4 只怪可杀死,就更新劳森的属性值…… 然后继续往后扫。
( 此题数据量大,用 scanf 会超时,所以要用输入输出挂…… )
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long Lint;
const int inf = 0x3f3f3f3f;
const int M = 1e5 + 100;
const int maxsize = 1e8;
char buf[maxsize];
int bufpos;
void init_read() {
buf[fread(buf, 1, maxsize, stdin)] = '\0';
bufpos = 0;
}
void in(int &x) {
x = 0;
for (; buf[bufpos] < '0' || buf[bufpos] > '9'; bufpos++);
for (; buf[bufpos] >= '0' && buf[bufpos] <= '9'; bufpos++) {
x = x * 10 + buf[bufpos] - '0';
}
}
struct Node{
int id;
int a[6];
int b[6];
int num;
}node[M];
struct Attr{
int val;
int ii;
}attr[6][M];
int n,k,swd[6],index[6];
bool cmp(Attr a1,Attr a2){
return a1.val<a2.val;
}
void input(){
in(n); in(k);
for(int i=0;i<k;i++) in(swd[i]);// scanf("%d",&swd[i]);
for(int i=0;i<n;i++){
node[i].num=0; node[i].id=i;
for(int j=0;j<k;j++){
in(node[i].a[j]); // scanf("%d",&node[i].a[j]);
attr[j][i].ii=i; attr[j][i].val=node[i].a[j];
}
for(int j=0;j<k;j++){
in(node[i].b[j]);//scanf("%d",&node[i].b[j]);
}
}
for(int i=0;i<k;i++)
sort(attr[i],attr[i]+n,cmp);
}
void deal(){
input();
int index[6],f=1;
for(int i=0;i<k;i++){
if(swd[i]<attr[i][0].val)
f=0;
}
if(f==0){
printf("0\n");
for(int i=0;i<k;i++){
printf("%d%c",swd[i],i==k-1?'\n':' ');
}
return;
}
int id,res=0,inin,sum=0;
memset(index,0,sizeof(index));
while(1){
sum=0;
for(int j=0;j<k;j++){
inin=index[j];
while( swd[j]>=attr[j][inin].val && inin<n ){
id=attr[j][inin].ii;
node[id].num++;
if(node[id].num==k){ //可以杀死
for(int jj=0;jj<k;jj++) swd[jj]+=node[id].b[jj]; //将属性值加上
res++;
}
sum++;
inin++;
}
index[j]=inin;
}
if(sum==0) break;
}
printf("%d\n",res);
for(int i=0;i<k;i++){
printf("%d%c",swd[i],i==k-1?'\n':' ');
}
return;
}
int main(){
init_read();
int t;
in(t);
while(t--)
deal();
return 0;
}