原题: http://acm.hdu.edu.cn/showproblem.php?pid=4544
//hdu 4544
//思路:为每一只兔子找能够杀死自己并且花费Q币最少的箭,关键在于不要超时,详细过程:
// 每一只兔子按血量从大到小排序,每一把箭按攻击值从大到小排序。接下来for循环,为每一只兔子找箭,
// 遍历每一只兔子,查找攻击值大于兔子血量的箭,把这些箭的Q币压入优先队列
// 能够杀死上一只兔子的箭一定能杀死下一只兔子,因为兔子的血量是从大到小排列的,把箭都压进队列后,
// 每次取优先队列的头(即Q币最小)的箭即可,但如果队列为空,表示没有一把剑能杀死当前的兔子,则跳出循环,输出No,有则继续遍历,直到遍历完所有的兔子。
//优先队列可以,multiset也可以,使用队列要注意自己重写一个cmp,用greater<int>会报编译错误。
//数据可能达到100亿,用long long
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
int rab[100001];
struct J
{
int di;
int pi;
}j[100001];
int cmp1(int a,int b)//按血量从大到小排序
{
return a>b;
}
int cmp2(J a,J b)//按伤害值由大到小排序
{
return a.di>b.di;
}
struct cmp //队列要用到的cmp结构体
{
bool operator ()(int a,int b)
{
return a>b;
}
};
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
for(int i=0;i<n;i++)
{
scanf("%d",&rab[i]);//兔子
}
for(int i=0;i<m;i++)//箭
{
scanf("%d",&j[i].di);
}
for(int i=0;i<m;i++)
{
scanf("%d",&j[i].pi);
}
if(n>m){//兔子数目大于箭的数目,不能杀死全部兔子
printf("No\n");
continue;
}
sort(rab,rab+n,cmp1); //排好序
sort(j,j+m,cmp2);
priority_queue<int,vector<int>,cmp>q1;//存放q币优先队列,由小到大
int k=0; //箭的下标
ll money=0;
int flag=1;//是否能够消灭全部兔子,flag=1能,flag=0不能
for(int i=0;i<n;i++)//遍历每一只兔子
{
int di=rab[i];//当前兔子的血量
for(;k<m;k++)
{
if(j[k].di>=di)//找那些可以杀死兔子的,把q币压入队列
{
q1.push(j[k].pi);
}else{
break;
}
}
if(q1.size()==0){//如果没有一支箭可以杀死这只兔子,flag=0,提前结束循环
flag=0;
break;
}else{
money=money+q1.top();
q1.pop();
}
}
if(flag){ //可以杀死全部兔子
printf("%lld\n",money);
}else{ //不能杀死全部兔子
printf("No\n");
}
}
return 0;
} //AC
有一道类似的题可以巩固加深 :
http://acm.hdu.edu.cn/showproblem.php?pid=4864