zoukankan      html  css  js  c++  java
  • bzoj2130: 魔塔

    Description

    魔塔是一款很流行的益智类小游戏。在游戏中,你可以控制主人公在魔塔中移动,走到怪兽面前便可以和怪兽来决斗,打败怪兽后可以得到金钱,并可以通过金钱来提高自己的攻击力、防御力、血量,从而变得更强大。然而,即便你拥有再高的攻击力、防御力,可以天下无敌,但一扇小小的门就可以阻止你无法前进。在游戏中,有红、黄、蓝三种颜色的门,并对应有红、黄、蓝三种颜色的钥匙。如果你想通过一扇门,需要消耗一把对应颜色的钥匙打开这扇门,如果你没有这种颜色的钥匙,便不能通过。现在你得到一款加强版的魔塔游戏:首先,门和钥匙的颜色不再是3种,而是n种,定为1~n号颜色。对于i号颜色的钥匙你有Ki把。并且之后你不会以任何形式得到任何颜色的钥匙。在你面前有三座n层的魔塔A、B、C。每座魔塔的入口处和相邻两层之间都会有一扇门。对于每座魔塔,恰好有n扇门,并且这n扇门的颜色恰好各不相同。其中,A魔塔中通往第i层的门颜色为DoorAi。(DoorBi、DoorCi的定义与DoorAi类似)在每座魔塔的每一层都有一定数量的怪兽,但这些怪兽根本打不过强大的你,你可以不费一滴血就秒杀这些怪兽,并得到杀死他们的金钱。我们已经为你统计好,消灭A魔塔第j层中所有的怪兽,可以得到的金钱数为GoldAi。(GoldBi、GoldCi的定义与GoldAi类似)现在,就请你来决策,如何运用这些钥匙,能得到最多的金钱,并告诉我们最多能获得多少金钱。

    Input

    第一行一个字符(A~F),表示数据类型(在下面数据规模中有详细介绍)第二行一个整数m,表示有几组测试数据。之后给出m组数据,对于每组数据有九行: 第一行一个整数n,表示魔塔层数。第二行一个数列Ki。第三行至第五行,每行一个数列,分别为DoorA、DoorB、DoorC。第六行至第八行,每行一个数列,分别为GoldA、GoldB、GoldC。第九行为一个空行。

    Output

    输出应包含m行,每行一个正整数,为最大能获得的金钱数。

    每个可行解的方案对应于三个魔塔各取一个前缀,可以用三个数(a,b,c)表示,因此这是一个三变量有约束的最值问题

    由于每一维对答案的贡献独立,考虑从小到大枚举一个变量c,降为二维(a,b),此时约束条件有两种:a<x||b<y,a<x&&b<y,可以用平衡树(可用std::set)维护max(b)关于a的函数(非严格递减,约束条件相当于对后缀取min,每次修改后更新答案)(如果用线段树维护则需要标记回收),用堆维护当前的最优解

    #include<bits/stdc++.h>
    const int N=100007,RN=1e5;
    char buf[N],*ptr=buf+RN;
    int G(){
        if(ptr==buf+RN)fread(ptr=buf,1,RN,stdin);
        return *ptr++;
    }
    int _(){
        int x=0;
        if(ptr<buf+RN-100){
            while(*ptr<48)++ptr;
            while(*ptr>47)x=x*10+*ptr++-48;
        }else{
            int c=G();
            while(c<48)c=G();
            while(c>47)x=x*10+c-48,c=G();
        }
        return x;
    }
    void maxs(int&a,int b){if(a<b)a=b;}
    void mins(int&a,int b){if(a>b)a=b;}
    int n,v[3][N],p,ws[2][N],xs[N],ks[N];
    std::priority_queue<int>q,qd;
    struct pos{
        mutable int l,x,y;
        bool operator<(pos w)const{return x<w.x;}
        void ins()const{q.push(v[1][x]+y);}
        void del()const{qd.push(v[1][x]+y);}
    }ps[N];
    typedef std::set<pos>ST;
    typedef ST::iterator IT;
    ST st;
    void cal(int x,int y){
        IT it=st.lower_bound((pos){0,x,0}),it_del;
        if(it->y<=y)return;
        int r1=-1;
        if(it->l<x){
            r1=it->x;
            it->del();
            it->x=x-1;
            it->ins();
            ++it;
        }
        for(;it!=st.end()&&it->y>y;it->del(),r1=it->x,it_del=it,++it,st.erase(it_del));
        st.insert((pos){x,r1,y}).first->ins();
    }
    int qmx(){
        while(qd.size()&&q.top()==qd.top())q.pop(),qd.pop();
        return q.top();
    }
    void work(){
        q=std::priority_queue<int>();
        qd=std::priority_queue<int>();
        st.clear();
        n=_();
        for(int i=1;i<=n;++i)ks[i]=_();
        for(int i=1;i<=n;++i)xs[i]=_();
        for(int t=0;t<2;++t){
            for(int i=1;i<=n;++i)ws[t][_()]=i;
        }
        for(int t=0;t<3;++t){
            for(int i=1;i<=n;++i)v[t][i]=v[t][i-1]+_();
        }
        st.insert((pos){0,n,v[2][n]}).first->ins();
        for(int i=1;i<=n;++i)if(ks[i]==1)cal(ws[0][i],v[2][ws[1][i]-1]);
        int ans=qmx();
        for(int i=1;i<=n;++i){
            int x=xs[i];
            int xp=ws[0][x],yp=ws[1][x];
            if(ks[x]==1){
                cal(0,v[2][yp-1]);
                cal(xp,-0x3f3f3f3f);
            }else{
                cal(xp,v[2][yp-1]);
            }
            maxs(ans,qmx()+v[0][i]);
        }
        printf("%d
    ",ans);
    }
    int main(){
        _();
        for(int T=_();T;--T)work();
        return 0;
    }
  • 相关阅读:
    bzoj3531[Sdoi2014]旅行
    bzoj3212 Pku3468 A Simple Problem with Integers 线段树
    bzoj1858[Scoi2010]序列操作 线段树
    bzoj2243[SDOI2011]染色 树链剖分+线段树
    bzoj3038上帝造题的七分钟2
    bzoj1036[ZJOI2008]树的统计Count 树链剖分+线段树
    bzoj3211花神游历各国 线段树
    bzoj4596[Shoi2016]黑暗前的幻想乡 Matrix定理+容斥原理
    bzoj3129[Sdoi2013]方程 exlucas+容斥原理
    刷题总结——寻宝游戏(bzoj3991 dfs序)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7269034.html
Copyright © 2011-2022 走看看