• JZOJ3404[NOIP2013模拟]卡牌游戏(2019.08.04[NOIP提高组]模拟 B 组T2)


    传送门

    卡牌游戏 (Standard IO)

    Time Limits: 1000 ms  Memory Limits: 524288 KB  Detailed Limits  

    Time to Submit: 01:59:17

    Description

    小X 为了展示自己高超的游戏技巧,在某一天兴致勃勃地找小Y 玩起了一种卡牌游戏。每张卡牌有类型(攻击或防御)和力量值两个信息。

    小Y 有n 张卡牌,小X 有m 张卡牌。已知小X 的卡牌全是攻击型的。

    游戏的每一轮都由小X 进行操作,首先从自己手上选择一张没有使用过的卡牌X。如果小Y 手上没有卡牌,受到的伤害为X 的力量值,否则小X 要从小Y 的手上选择一张卡牌Y。若Y 是攻击型(当X 的力量值不小于Y 的力量值时才可选择),此轮结束后Y 消失,小Y 受到的伤害为X 的力量值与Y 的力量值的差;若Y 是防御型(当X 的力量值大于Y 的力量值时才可选择),此轮结束后Y 消失,小Y 不受到伤害。

    小X 可以随时结束自己的操作(卡牌不一定要用完)。希望聪明的你帮助他进行操作,使得小Y 受到的总伤害最大。

    Input

    输入的第一行包含两个整数n 和m 。

    接下来n 行每行包含一个字符串和一个整数,分别表示小Y 的一张卡牌的类型(“ATK”表示攻击型,“DEF”表示防御型)和力量值。

    接下来m 行每行包含一个整数,表示小X 的一张卡牌的力量值。

    Output

    输出一行包含一个整数,表示小Y 受到的最大总伤害。

    Sample Input

    输入1:

    2 3

    ATK 2000

    DEF 1700

    2500

    2500

    2500

    输入2:

    3 4

    ATK 10

    ATK 100

    ATK 1000

    1

    11

    101

    1001

    Sample Output

    输出1:

    3000

    【样例说明1】

    第一轮,小X 选择自己的第一张卡牌和小Y 的第二张卡牌,小Y 的第二张卡牌消失。

    第二轮,小X 选择自己的第二张卡牌和小Y 的第一张卡牌,小Y 的第一张卡牌消失,同时受到500 点伤害。

    第三轮,小X 选择自己的第三张卡牌,此时小Y 手上已经没有卡牌,受到2500 点伤害。

    小X 结束游戏,小Y 共受到3000点伤害。

    输出2:

    992

    【样例说明2】

    第一轮,小X 选择自己的第三张卡牌和小Y 的第一张卡牌,小Y 的第一张卡牌消失,同时受到91点伤害。

    第二轮,小X 选择自己的第四张卡牌和小Y 的第二张卡牌,小Y 的第二张卡牌消失,同时受到901点伤害。

    小X 结束游戏,小Y 共受到992点伤害。

     

    Data Constraint

    各规模均有一半数据满足小Y 只有攻击型卡牌。

    对于30%的数据,1≤ n,m ≤ 6。

    对于60%的数据,1≤ n,m ≤10^3。

    对于100%的数据,1≤ n,m ≤10^5,力量值均为不超过10^6的非负整数。

     一、暴力搜索(30)

    这个题目前能保证正确的貌似是这个搜索,然而它是会TLE的。

    #include<bits/stdc++.h>
    using namespace std;
    inline int poread()
    {
        char c = 0;
        int res = 0;
        while(!isdigit(c = getchar()));
        do
        {
            res = res * 10 + c - 48;
        }
        while(isdigit(c = getchar()));
        return res;
    }
    const int MAXN = 1e5 + 5;
    int n,m;
    struct node
    {
        bool isstack;
        int force;
    }Y[MAXN];
    int X[MAXN];
    bool v_Y[MAXN],v_X[MAXN];
    int ans;
    void dfs(int now,int cnt)
    {
        ans = max(ans,now);
    //    cerr<<cnt<<":"<<now<<" "<<x<<" "<<y<<endl;
    //    for(register int i = 1; i <= n; ++i)
    //        cerr<<v_Y[i];
    //    cerr<<endl;
    //    for(register int i = 1; i <= m; ++i)
    //        cerr<<v_X[i];
    //    cerr<<endl;
        if(cnt > m )
        {
            return;
        }
        int sum = now;
        if(cnt >= n)
        {
            for(register int j = 1; j <= m; ++j)
            {
                if(!v_X[j])
                {
                    
                    sum = now;
                    v_X[j] = true;
                    sum += X[j];
                    dfs(sum, cnt + 1);
                    v_X[j] = false;
                }
                
            }
        }
        else
        {
            for(register int i = 1; i <= n; ++i) 
            {
                if(!v_Y[i])
                {
                    for(register int j = 1; j <= m; ++j) 
                    {
                        
                        if(!v_X[j])
                        {
                            sum = now;
                            
                            if(Y[i].isstack)
                            {
                                if(X[j] < Y[i].force)
                                    continue;
                                sum += (X[j] - Y[i].force);
                            }
                            else
                            {
                                if(X[j] <= Y[i].force)
                                    continue;
                            }
                            v_Y[i] = true, v_X[j] = true;
                            dfs(sum,cnt + 1);
                            v_Y[i] = false,    v_X[j] = false;
                        }
                    }
                }    
            }    
        }        
    }
    int main()
    {
    #ifdef lky233
        freopen("testdata.in","r",stdin);
        freopen("testdata.out","w",stdout);
    #endif
        n = poread();
        m = poread();
        for(register int i = 1; i <= n; ++i)
        {
            char s[10];
            scanf("%s",s);
            Y[i].force = poread();
            Y[i].isstack = (s[0] == 'A');
        }
        for(register int i = 1; i <= m; ++i)
        {
            X[i] = poread();
        }
        dfs(0,0);
        cout<<ans<<endl;
    }

    二、出锅的贪心

    这个贪心策略是这样的,首先对于这个问题,有两种策略:

      1、直接攻击对方的攻击牌,拿到分数后结束游戏。

        师曰:对于这个策略,我们将x从大到小排序,y从小到大排序,一直攻击直到结束。

        对于样例2,该策略可以通过,而且原本是A了这个题的。

        Hack:  

        2 3
        ATK 599
        ATK 1000
        1200
        600
        450

        显然如果使用上述策略,ans = 601,但是1200->1000,600->599,450->脸,会获得651的分数。

      2、拿光对手的所有牌,并用自己的牌打对方脸直接攻击。

        对于这个策略,应该用最小的消耗解除掉对答案没有产生贡献的盾牌,之后使用策略1攻击攻击牌,最后打脸。

        对于出锅的数据,采用了把y从大到小排一遍进行计算然后取max的方式过掉了。(面向数据编程大法)

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int poread()
    {
        char c = 0;
        int res = 0;
        while(!isdigit(c = getchar()));
        do
        {
            res = res * 10 + c - 48;
        }
        while(isdigit(c = getchar()));
        return res;
    }
    const int MAXN = 1e5 + 7;
    int n,m;
    int ans_1,ans_2,ans_3;
    struct node
    {
        int x;
        bool isstack;
        void in()
        {
            char s[10];
            scanf("%s",s);
            isstack = (s[0] == 'A');
            x = poread();
        }
    }datax[MAXN],datay[MAXN],x[MAXN],y[MAXN],tmpdata[MAXN];
    bool cmp1(node a,node b)//从小到大 
    {
        return a.x < b.x;
    }
    bool cmp2(node a,node b)//从大到小
    {
        return a.x > b.x;
    }
    void tan_1()//只打掉Attack 
    {
        int tmpans_1 = 0,tmpans_2 = 0;
        int tmpm = 0,tmpn = 0;
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memcpy(x,datax,sizeof(datax));
        for(register int i = 1;i <= n; ++i)
        {
            if(datay[i].isstack)
                y[++tmpn] = datay[i];
        }
        sort(y+1,y+tmpn+1,cmp1);
        sort(x+1,x+m+1,cmp2);
        int nn = min(tmpn,m);
        for(register int i = 1; i <= nn; ++i)
        {
            if(x[i].x < y[i].x)
                break;
            tmpans_1 += x[i].x - y[i].x;
        }
        sort(y+1,y+tmpn+1,cmp2);
        for(register int i = 1; i <= nn; ++i)
        {
            if(x[i].x < y[i].x)
                break;
            tmpans_2 += x[i].x - y[i].x;
        }
        ans_1 = max(tmpans_1,tmpans_2);
    }
    bool v[MAXN];
    void tan_2()
    {
        if(n > m)
        {
            ans_2 = 0;
            return;
        }
        int tmpans_1 = 0,tmpans_2 = 0;
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        for(register int i = 1; i <= m; ++i)
        {
            tmpdata[i] = datax[i];
        }
        int tmpm = 0,tmpn = 0;
        for(register int i = 1; i <= n; ++i)
        {
            if(!datay[i].isstack)
                y[++tmpn] = datay[i];
        }
        //双指针,破盾 
        sort(tmpdata+1,tmpdata+m+1,cmp1);
        sort(y+1,y+tmpn+1,cmp1);
        int point1 = 1,point2 = 1,tmp_cnt = 0;
    
        while(point1 <= m && point2 <= tmpn)
        {
    //        cerr<<point1<<endl;
            while(tmpdata[point1].x <= y[point2].x)
            {
                if(point1 > m)
                    break;
                ++point1;
            }
            if(tmpdata[point1].x > y[point2].x)
                ++tmp_cnt,v[point1] = true;
            ++point2;
            ++point1;
        }
    //    cerr<<1<<endl;
        //不能打破所有的盾,这个策略不可行。 
        if(tmp_cnt < tmpn)
        {
            ans_3 = 0;
            return;
        }
        tmpn = tmpm = 0;
        for(register int i = 1; i <= m; ++i)
        {
            if(!v[i])
                x[++tmpm] = tmpdata[i];    
        }
        memset(y,0,sizeof(y));
        for(register int i = 1; i <= n; ++i)
        {
            if(datay[i].isstack)
                y[++tmpn] = datay[i];
        }
        
        
        sort(y+1,y+tmpn+1,cmp1);
        sort(x+1,x+tmpm+1,cmp2);
        int nn = min(tmpn,tmpm),mm = max(tmpn,tmpm);
        #ifdef lky233
        for(register int i = 1; i <= tmpm; ++i)
            cerr << x[i].x << endl;
        for(register int i = 1; i <= tmpn; ++i)
            cerr << y[i].x << endl;
        #endif
        bool con = 1;
        for(register int i = 1; i <= nn; ++i)
        {
            if(x[i].x < y[i].x)
            {
                con = 0;
                break;
            }
            tmpans_1 += x[i].x - y[i].x;
        }
        if(con)
            for(register int i = nn + 1; i <= mm; ++i)
            {
                tmpans_1 += x[i].x;
            }
        con = 1;
        sort(y+1,y+tmpn+1,cmp2);
        for(register int i = 1; i <= nn; ++i)
        {
            if(x[i].x < y[i].x)
            {
                con = 0;
                break;
            }
            tmpans_2 += x[i].x - y[i].x;
        }
        if(con)
            for(register int i = nn + 1; i <= mm; ++i)
            {
                tmpans_2 += x[i].x;
            }
        ans_2 = max(tmpans_1,tmpans_2);
    //    cerr<<tmpans_1<<' '<<tmpans_2<<endl;
        return;
    }
    signed main()
    {
    #ifdef lky233
        freopen("testdata.in","r",stdin);
        freopen("testdata.out","w",stdout);
    #endif
        n = poread();
        m = poread();
        for(register int i = 1; i <= n; ++i)
            datay[i].in();
        for(register int i = 1; i <= m; ++i)
            datax[i].x = poread();
        tan_1();
        tan_2();
    //    cerr<<ans_1<<" "<<ans_2<<endl;
        cout<<max(ans_1,ans_2)<<endl;
        return 0;
    }

    冗余代码极多还能优化……

    三、意识到贪心是正确的然后来补充

    Hack数据实际可认为是策略2。

    策略2修正:破掉对方的盾牌,之后己方sigma Attack - 对方 sigma Attack;

    策略1证明: 使用一个更小的数攻击对方的数,会减小贡献值。

    策略2: 只要可以破掉对方盾牌,攻击顺序其实已经不会影响最终答案了……

    代码咕咕咕掉,回宿舍了。

  • 相关阅读:
    [BZOJ 1552] 排序机械臂
    [BZOJ 1124][POI 2008] 枪战 Maf
    [BZOJ 1647][USACO 2007 Open] Fliptile 翻格子游戏
    [BZOJ 1592] Making The Grade路面修整
    [BZOJ 3829][POI2014] FarmCraft
    [技术] 如何正确食用cnblogs的CSS定制
    [BZOJ 1458] 士兵占领
    今天写了一个Imageloader,,AndroidStudio报了Error:Execution failed for task ':app:mergeDebugResources'. > Error: Java.util.concurrent.ExecutionException: com.Android.ide.common.process.ProcessException: 这个错误
    Http响应码代表的含义
    获取WIFI列表,在旧手机上运行就没有问题,在新手机上就怎么也获取不到WIFI列表,长度一直为0,还不报异常,很疑惑。
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11300035.html
Copyright © 2020-2023  润新知