hdu个人赛6—1009

对抗女巫的魔法碎片

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
光明世界的一个国家发生动荡,女巫利用了邪恶的力量将国家的村庄都施下了咒语,好在国家还有英勇 的士兵,他们正义的力量能够破解这些魔咒夺回村庄,并且得到魔法碎片,利用足够多的魔法碎片可以将女巫铲除。
现在己经被魔咒封印的村庄有m个,编号为1到m。英勇的士兵n个,编号从1到n。第i个士兵攻击力 为 ai ,第j个村庄防御力为 bj ,魔法价值为 cj
现在这些士兵想夺回这些村庄,每个士兵可以最多占领一个村庄,一个村庄最多被一个士兵占领。当士兵的攻击力 ai 大于村庄的防御力 bj 的时候,该士兵就可以夺回这个村庄,并且士兵会获得魔法碎片 aibj+cj  个。
现在想知道这些士兵夺回村庄,获得的魔法碎片之和最多是多少
 

Input
输入第一行一个整数T,表示有T组数据。
接下来一行输入两个整数n和m。
接下来一行,输入n个数 ai ,表示士兵的攻击力。
接下来m行,每行输入两个数 bici ,表示村庄的防御力和该村庄的魔法价值。
1 <= n,m <= 100000
1 <=  ai,bi,ci  <= 100000
 

Output
一个整数,表示获得的魔法碎片的数量
 

Sample Input
  
  
2 3 3 4 4 4 2 3 1 3 5 3 3 3 4 4 6 2 3 4 3 5 3
 

Sample Output
  
  
11 10
 

【分析】

先说一下,这道题的题目是有问题的,在贪心的情况下,肯定是会优先选择村庄数量优先,也就是每次用最靠近村庄防御力的士兵去占领这个村庄,计算出能占领ans个村庄,然后最后从士兵攻击力从高到低取前ans个就可以了,村庄的贡献就是c[i]-b[i],按照贡献排序。

一组数据
1
2 2
2 10
1 3
9 3
贪心结果是8
正确答案应该是攻击10的士兵占领防御为1的村庄,答案为12

所以正确算法不是贪心....按照大佬讲的是如果你把所有按照a,b排序的话(a,b)放一起,那么就是找一个合法的括号序列使得价值最大,因此线段树贪心取出最大的()或者)(即可(需要满足取出之后合法)。

//这里留一个贪心的错误代码...虽然是AC的但是还是错误代码。。。陈老师的线段树模拟费用流...我不会写啊QAQ

【代码】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;  

struct xx{
    int x,y,c;
}f[100010];

int id[100010];
int a[100010];

bool cmp(const int&q,const int&w)
{
    return f[q].c>f[w].c;
}
bool cmp1(const int&q,const int&w)
{
    return q>w; 
}
multiset<int>s;
multiset<int>::iterator it;
int main()  
{  
     int pp;scanf("%d",&pp);
    while(pp--)  
    {  
        int n,m;scanf("%d%d",&n,&m);  
        s.clear();
        for(int i=0;i<n;i++) 
        {
            scanf("%d",&a[i]);  
            s.insert(a[i]);
        }
        sort(a,a+n,cmp1);
        for(int i=0;i<m;i++)  
        {  
            scanf("%d%d",&f[i].x,&f[i].y);  
            f[i].c=f[i].y-f[i].x;
            id[i]=i;
        }  
        sort(id,id+m,cmp);
        long long ans=0;
        int len=0;
        for(int i=0;i<m;i++)  
        {  
            it=s.lower_bound(f[id[i]].x);
            while (*it==f[id[i]].x)it++;
            if (it!=s.end())
            {
                s.erase(it);
                ans+=f[id[i]].c;
                len++;
            }
        }  
        //printf("%d\n",len);
        for(int i=0;i<n&&i<len;i++)  
            ans+=a[i];  
        printf("%lld\n",ans);  
    }  
    return 0;  
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值