(HDU6396)2018 Multi-University Training Contest 7 - 1011 - Swordsman - 优先队列+快读模板

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6396

题解全部“改编”“抄袭”自IGVA大佬的博客:https://blog.csdn.net/LSD20164388/article/details/81637550

题意:一个剑客有k种属性,有n个怪物每个怪物也有k种属性与k种加成,如果剑客的每种属性都大于某个怪物的对应属性,那么剑客将杀死此怪物,而且剑客的每种属性都要加上此怪物对应的加成,问剑客最终能杀死几个怪物和最终剑客的每种属性值。

解析

思路:优先队列。用k个优先队列(队列存一个pair存<属性值,怪物编号>,默认按第一个排序,设置升序),队列q[i]是存放怪物的第i种属性。首先把所有怪的第1个属性和怪的编号(用pair)加入到第一个队列当中。每次外层循环查询所有队列(第一个到第m个队列),即从第1个属性开始到第m个属性,如果当前属性小于等于你的属性,就把这个怪的下一个属性和怪的编号加入到下一个优先队列中。直到最后一个优先队列中对应的属性小于等于你的最后一个属性,就累加吃掉这个怪你能提高的每个属性的值。然后此时你的各项属性都已经提高,再重复此操作直到吃掉的怪数不再变化。然而这样还是会TLE。需要抄一个超神输入挂。

优先队列用法:https://blog.csdn.net/pzhu_cg_csdn/article/details/79166858

代码

//IGVA
#include<bits/stdc++.h>
#define ll long long
using namespace std;

namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc()
{
    static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
    if(p1 == pend)
    {
        p1 = buf;
        pend = buf + fread(buf, 1, BUF_SIZE, stdin);
        if(pend == p1)
        {
            IOerror = 1;
            return -1;
        }
    }
    return *p1++;
}
inline bool blank(char ch)
{
    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x)
{
    char ch;
    while(blank(ch = nc()));
    if(IOerror) return;
    for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
// void read(int &x){scanf("%d",&x);} //调试的时候用这个,把上面的注释掉。

const int maxn=100010;
int n,m,k,a[maxn][10],b[maxn][10],v[maxn];
typedef pair<int, int> pp;
typedef priority_queue< pp, vector<pp>, greater<pp> > QQ;//队列只存放pp一个值
QQ q[10],p;
int main()
{
    int T,cas=1;
    read(T);
    while(T--)
    {
        read(n);
        read(m);
        for(int i=0; i<m; i++) read(v[i]);
        for(int i=0; i<m; i++) q[i]=QQ();
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
                read(a[i][j]);
            q[0].push({a[i][0],i});
            for(int j=0; j<m; j++)
                read(b[i][j]);
        }
        int ans=0,tmp=-1;
        while(tmp!=ans)//ans有更新时继续循环,因为吃掉怪物是自己属性有更新所以这里要循环
        {
            tmp=ans;
            for(int i=0; i<m-1; i++)//处理前m-1种属性,q[i]是存放怪物的第i种属性
            {
                while(!q[i].empty()&&q[i].top().first<=v[i])//处理对于第i种属性能解决的怪物
                {
                    int x=q[i].top().second;
                    q[i].pop();
                    q[i+1].push({a[x][i+1],x});
                }
            }
            while(!q[m-1].empty()&&q[m-1].top().first<=v[m-1])//处理最后一种属性,此时可能有怪物被杀死
            {
                int x=q[m-1].top().second;
                q[m-1].pop();
                ++ans;
                for(int i=0; i<m; i++)
                    v[i]+=b[x][i];
            }
        }
        int flag=1;
        printf("%d\n",ans);
        for(int i=0; i<m; i++)
            if(flag)
            {
                flag=0;
                printf("%d",v[i]);
            }
            else printf(" %d",v[i]);
        puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/81671421