【贪心】(雾)小Y的炮

【问题描述】
小Y最近开发出了批量制造大威力轰山炮的方法。才过去不到几个月,小Y就制造出了M门款式不同的轰山炮。第i门轰山炮发射一次,能使一座当前高度不高于Ai的山的高度降低Di(当然山的高度不能轰到0以下)。应政府要求,小Y要用他开发的轰山炮轰平开发
区的几座山。由于开发区急需土地资源,政府要求小Y轰平尽量多的山(轰平:使山的高度降低至0)。但是小Y制造的弹药有限,导致他最多只能发射K次。小Y想知道,他最多能轰平几座山?轰平这些山后,弹药最多还够他发射几次?

【问题分析】

贪心
如果一个炮相比于另一个炮(意大利),打的没它高,削减高度没它多,那你还用它干毛?对不对。这样的话时间代价O(NM),但是我常数写的大,O(10^7)过了一半的点。MD。

优化

预处理出所有山都需要几炮干掉 虽然确定是一个个连续的区间,但是山太高了 存不下啊 而且还存在特殊数据 比如说某一个炮d>h的时候,当山高h+1时,并且下一个炮d>h+1时,就不好处理。。。

所以 咋整? 考试的时候真的没有想出来。

观察 D<=500 ???
所以说为了避免上述情况 可以将每一个炮的[h-d,h]处理出来就可以了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
#define ll long long
const int N=250001;
const int M=501;
map<ll,ll> f;
struct gg {ll h;int d;}pao[M],use[M];
int n,m,cnt; ll hill[N]; ll k,ans;
ll readin()
{
    ll x=0,f=1; char ch=getchar();
    while(ch>'9'||ch<'0') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool cmp(gg a,gg b)
{
    if (a.h==b.h)
        return a.d<b.d;
    return a.h<b.h;
}
void read()
{
    int i;
    n=readin(); m=readin(); k=readin();
    for (i=n;i>=1;i--)
        hill[i]=readin();
    for (i=1;i<=m;i++)
        pao[i].h=readin(),pao[i].d=readin();
    sort(pao+1,pao+1+m,cmp);
    pao[0]=(gg){0,0};
    for (i=1;i<=m;i++)
    {
        while(cnt&&use[cnt].d<=pao[i].d) cnt--;
        use[++cnt]=pao[i];
    }
    use[0]=(gg){0,0};
    return;
}
long long mymax(long long a,long long b){return a>b?a:b;}
void solve()
{
    ll now=0,l,j,tmp; int i;
    f[0]=0;
    for (i=1;i<=cnt;i++)
    {
        now=use[i-1].h;
        l=mymax(now,use[i].h-use[i].d);
        for (j=l+1;j<=use[i].h;j++)
        {
            tmp=(j-now-1)/use[i].d+1;
            f[j]=f[mymax(0,j-(use[i].d*tmp))]+tmp;
        }
    }
    return;
}
void work()
{
    int i,j=1; ll now,tmp,need;
    for (i=1;i<=n;i++)
    {
        while(j<=cnt&&use[j].h<hill[i]) j++;
        if (j>cnt)
        {
            printf("%d %lld\n",i-1,k-ans);
            return;
        }
        now=use[j-1].h;
        tmp=(hill[i]-now-1)/use[j].d+1;
        need=f[mymax(0,hill[i]-(use[j].d*tmp))]+tmp;
        if (ans+need>k)
        {
            printf("%d %lld\n",i-1,k-ans);
            return;
        }
        ans+=need;
    }
    printf("%d %lld\n",n,k-ans);
    return;
}
int main()
{
    freopen("canon.in","r",stdin);
    freopen("cannon.out","w",stdout);
    read();
    solve();
    work();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值