刷怪升级

3 篇文章 0 订阅
1 篇文章 0 订阅

【问题描述】

小 A 小 B 小 C 要共同协作刷掉 n 个怪物才可通关升级,其中第 i 个怪物拥有 a[i]的物理防御力,b[i]的魔法防御力,c[i]的精神防御力。如果想要打死第 i 只怪物,需要自身的物理攻击力不小于 a[i]或者魔法攻击力不小于 b[i]或者精神攻击力不小于 c[i]。
他们经过简单的计算发现其实每个人只要专注于提升三种攻击力中的一种即可,因为这一定更划算。无论提升哪种攻击力,每提升 1 个单位攻击需要花费 1 个单位的钱。起初他们的所有攻击力均为 0,问他们最小需要多少单位的钱即可刷掉 n 个怪物。

【输入】

第一行一个数 n,表示 n 个怪物。
接下来 n 行,每行三个数 ai, bi, ci 表示一只怪物的物理防御力,魔法防御力和精神防
御力。

【输出】

一行一个数,表示需要最少花费多少单位的钱。

【输入输出样例】
Input
3
2 2 100
1 100 3
100 4 5
Output
5

【样例解释】

A = {(1, 100, 3)}
B = {(100, 4, 5),(2, 2, 100)}
C = {}
小 A 负责打第二个怪物,小 A 只需提升 1 点物理攻击即可打败。
小 B 负责打第一个和第三个怪物,需要提升 4 点魔法攻击。
小 C 负责加油助♂威。
共需花费 1+4=5 个单位的钱。

【数据范围与约定】

存在 30%的数据,1 <= n <= 300, 1 <= ai, bi, ci <= 300
存在 40%的数据,1 <= n <= 100000, 1 <= ai,bi <= 100000, ci 均为 100000000
存在 20%的数据,1 <= n <= 100000, 1 <= ai, bi, ci <= 100000
存在 10%的数据,1 <= n <= 100000, 1 <= ai, bi, ci <= 100000000
上述数据覆盖约束覆盖了 100%的测试数据。

【题解】

这道题好像有几种方法:

方法一:暴力乱搞

复杂度指数级别,竟然过了,还跑的比其他方法都快orzorzorzorzorz…..
完美诠释“骗分过样例,暴力出奇迹”)

#include<cstdio> 
#include<iostream> 
#include<cstring> 
using namespace std;
int n;
int a[100001],b[100001],c[100001];
int ans=1<<30;
void dfs(int u,int x,int y,int z)
{
    if(x+y+z>=ans)return;
    if(u==n+1)
    {
        ans=min(ans,x+y+z);
        return;
    }
    if(a[u]<=x||b[u]<=y||c[u]<=z)
    {
        dfs(u+1,x,y,z);
        return;
    }
    dfs(u+1,a[u],y,z);
    dfs(u+1,x,b[u],z);
    dfs(u+1,x,y,c[u]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    dfs(1,0,0,0);
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
} 

方法二:线段树(什么鬼思想搞不懂,看来我听学长讲课时要做笔记了)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX=150005;
int n,m,B,C,b[MAX],o[MAX],ans=2147483647;
struct segtree
{
    int mn,mc;
    int lazy;
}t[MAX<<2];
struct node{int a,b,c;}w[MAX];
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=-1,ch=getchar();
    while (ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*w;
}
bool cmp(node x,node y) {return x.a<y.a;}
void Pushdown(int now,int l,int r)
{
    if (!t[now].lazy) return;
    int mid=l+r>>1;
    t[now<<1].mn=b[l]+t[now].lazy;
    t[now<<1|1].mn=b[mid+1]+t[now].lazy;
    t[now<<1].mc=t[now].lazy;t[now<<1].lazy=t[now].lazy;
    t[now<<1|1].mc=t[now].lazy;t[now<<1|1].lazy=t[now].lazy;
    t[now].lazy=0;
}
void Update(int now)
{
    t[now].mn=min(t[now<<1].mn,t[now<<1|1].mn);
    t[now].mc=min(t[now<<1].mc,t[now<<1|1].mc);
}
void Build(int now,int l,int r)
{
    if (l==r)
    {
        t[now].mn=b[l];
        return;
    }
    int mid=l+r>>1;
    Build(now<<1,l,mid);
    Build(now<<1|1,mid+1,r);
    Update(now);
}
int Query(int now,int l,int r,int ql,int qr,int val)
{
    Pushdown(now,l,r);
    if (t[now].mc>=val) return 0;
    if (l==r) return l;
    int mid=l+r>>1,res=0;
    if (ql<=mid) res=Query(now<<1,l,mid,ql,qr,val);
    if (qr>mid&&!res) res=Query(now<<1|1,mid+1,r,ql,qr,val);
    Update(now);
    return res;
}
void Modify(int now,int l,int r,int ql,int qr,int val)
{
    Pushdown(now,l,r);
    if (l>=ql&&r<=qr)
    {
        t[now].mn=b[l]+val;t[now].mc=val;t[now].lazy=val;
        return;
    }
    int mid=l+r>>1;
    if (ql<=mid) Modify(now<<1,l,mid,ql,qr,val);
    if (qr>mid) Modify(now<<1|1,mid+1,r,ql,qr,val);
    Update(now);
}
int main()
{
    //freopen("playwithboss.in","r",stdin);
    //freopen("playwithboss.out","w",stdout);
    n=gi();
    for (int i=1;i<=n;i++) w[i]=(node){gi(),gi(),gi()};
    for (int i=1;i<=n;i++) b[i]=w[i].b;
    sort(b+1,b+n+1);
    m=unique(b+1,b+n+1)-b-1;
    //for (int i=1;i<=m;i++) b[i]=o[i];
    for (int i=1;i<=n;i++) w[i].b=lower_bound(b+1,b+m+1,w[i].b)-b;
    Build(1,1,m);
    sort(w+1,w+n+1,cmp);
    for (int i=n;i>0;i--)
    {
        Pushdown(1,1,m);
        ans=min(ans,w[i].a+t[1].mn);
        ans=min(ans,C+w[i].a),C=max(C,w[i].c);
        ans=min(ans,B+w[i].a),B=max(B,b[w[i].b]);
        if (w[i].b>1)
        {
            int t=Query(1,1,m,1,w[i].b-1,w[i].c);
            if (t) Modify(1,1,m,t,w[i].b-1,w[i].c); 
        }
    }
    Pushdown(1,1,m);
    ans=min(ans,t[1].mn);
    ans=min(ans,C);
    ans=min(ans,B);
    //for (int i=1;i<=20;i++)
    //  printf("now=%d mn=%d mc=%d lazy=%d\n",i,t[i].mn,t[i].mc,t[i].lazy);
    printf("%d",ans);
    return 0;
}

方法三:set(还是搞不懂QAQ)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
typedef pair<int,int> pir;
const int N=100010,Inf=1<<30;
int n;
int a[N],b[N],c[N],id[N];
set <pir> w;
inline int gi() {
    int x=0,o=1;
    char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') ch=getchar(),o=-1;
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*o;
}
struct Que {
    priority_queue <int,vector<int>,greater<int> > p,q;
    inline void push(int x) {p.push(x);}
    inline void delet(int x) {q.push(x);}
    inline int top() {
    while(!q.empty()&&p.top()==q.top()) p.pop(),q.pop();
    return p.top();
    }
} Q;
inline bool cmp(const int &x,const int &y) {
    return a[x]>a[y];
}
inline void insert(int x) {
    set <pir> :: iterator t=w.lower_bound(pir(b[x],c[x])),p;
    if(t->second>=c[x]) return;
    if(t->first>b[x]) --t;
    while(1) {
    if(t->second>c[x]) {
        Q.delet(t->first+(++t)->second);
        t=w.insert(pir(b[x],c[x])).first;
        Q.push(c[x]+(--t)->first);
        ++t,Q.push(b[x]+(++t)->second);
        return;
    }
    Q.delet(t->second+(p=--t)->first);
    ++t,Q.delet(t->first+(++t)->second);
    Q.push(p->first+t->second);
    w.erase(--t),t=p;
    }
}
int main() {
    int ans=Inf  ;
    cin>>n;
    for(int i=1;i<=n;i++) a[i]=gi(),b[i]=gi(),c[i]=gi(),id[i]=i;
    sort(id+1,id+1+n,cmp);
    Q.push(0);
    w.insert(pir(0,Inf)),w.insert(pir(Inf,0));
    for(int i=1;i<=n;i++) {
    ans=min(ans,a[id[i]]+Q.top());
    insert(id[i]);
    }
    cout<<min(ans,Q.top());
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值