zoukankan      html  css  js  c++  java
  • Easy 2048 Again

    Easy 2048 Again

    Time Limit: 2 Seconds      Memory Limit: 65536 KB

    Dark_sun knows that on a single-track road (which means once he passed this area, he cannot come back again), there are some underground treasures on each area of the road which has the value of 2, 4, 8 or 16. Dark_sun can decide whether to dig them or not in order to get the highest score. The calculation rule of the total score is similar to the game Flappy 2048.

    Dark_sun's bag is like a queue. When he gets a treasure, the treasure will be pushed back into the end of the bag. And the score will add the value of the treasure. For example, when there are treasures on the road in the order of {2, 8, 4, 8} and if Dark_sun decides to dig all of them, he will get the final score of 2+8+4+8=22. And his bag will finally become the sequence of {2, 8, 4, 8}.

    If the adjacent treasures in the Dark_sun's bag have the same value, they will mix into a bigger treasure which has the value of their sum (the double value of the previous one). And Dark_sun will get a combo score of the value of bigger treasure. For example in the previous case, if Dark_sun decides to dig only the {2, 8, 8} treasure in sequence. He will get the basic score of 18(2+8+8). And when the last treasure (value 8) is pushed back into his bag, his bag will turn {2, 8, 8} into {2, 16} and he will get a bonus score of 16. And his final score will become 18+16=34 (which is the best strategy in this case.)

    Notice that the treasures mix to the bigger one automatically when there are the same adjacent treasures. For example, when there are treasures of {2, 2, 4, 8, 16} on the road, and if Dark_sun decides to dig all of them, he will get the basic score of 32(2+2+4+8+16) and a bonus score of 60(4+8+16+32). At last he will get the total score of 92 and the bag becomes {32}.

    Now, Dark_sun wants to get the highest score (no matter what's the treasure in his bag), can you tell him the what's the highest score?

    Input

    The first line is an integer n, which is the case number. In each case, the first line is an integer L, which is the length of the road.(0 < L ≤ 500) The second line contains L integers which can only be 2, 4, 8 or 16. This means the value of treasure on each area of the road.

    Output

    For each case, you should output an integer. The answer is the maximum of the total score which Dark_sun may get.

    Sample Input

    3
    4
    2 8 4 8
    5
    2 2 4 8 16
    8
    8 4 4 2 8 4 2 2
    

    Sample Output

    34
    92
    116
    

    Hint

    In the third sample case, Dark_sun will choose {8,4,4,8,4,2,2}. Firstly, the first three treasures will be combined to 16 and then the {16,8,4,2,2} will become 32. And he will get the basic score 32(8+4+4+8+4+2+2) and the bonus score 84(8+16+4+8+16+32).


    题意:对于一个序列,你能够按顺序选或不选一些数。然后放在一个栈里。假设两个一样的数在一起就会合并,你的得分是放的数加上合并成的数的总和,问最后得分最多是多少。

    思路:状压dp,这道题本身就是二进制,也就方便了,注意要用滚动数组。不然会爆MLE。

         这里用滚动数组记录你在选第n个数的时候之前的状压情况和得分。

    AC代码例如以下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    using namespace std;
    typedef long long ll;
    map<ll,ll> match[2];
    ll F[1000010][2];
    int vis[1000010];
    ll ans;
    void solve(ll S,ll k,int pos,int pos2)
    { F[0][pos2]++;
      F[F[0][pos2]][pos2]=S; //不选这个数,保留原状压情况
      match[pos2][S]=max(match[pos2][S],match[pos][S]);
      if((S%k)!=0) //选这个数。而且之前状压情况有比k小的数。比方之前的状压结果为8 4 2 这时你增加一个4,那么队列里面就会是 8 4 2 4,
                   //前三个数都不可能再去合并了。所以状压结果仅仅要保留k就能够了 
      { match[pos2][k]=max(match[pos2][k],match[pos][S]+k);
        F[0][pos2]++;
        F[F[0][pos2]][pos2]=k;
        ans=max(ans,match[pos2][k]);
        return;
      }
      ll ret=k,S2=S;
      while((S&k)!=0) //合并同样的数
      { S-=k;
        k*=2;
        ret+=k;
      }
      S+=k;
      match[pos2][S]=max(match[pos2][S],match[pos][S2]+ret);
      ans=max(ans,match[pos2][S]);
      F[0][pos2]++;
      F[F[0][pos2]][pos2]=S;
    }
    int main()
    { int t,n,i,j,k,len,a,b,pos=0;
      scanf("%d",&t);
      while(t--)
      { scanf("%d",&n);
        match[0].clear();match[1].clear();
        F[0][0]=1;F[1][0]=0;
        match[0][0]=0;
        ans=0;
        for(i=1;i<=n;i++)
        { pos++;
          scanf("%lld",&k);
          if(i&1)
          { a=0;b=1;}
          else
          { a=1;b=0;}
          match[b].clear();
          F[0][b]=0;
          for(j=1;j<=F[0][a];j++) // F[0][a]记录之前有多少种情况
           if(vis[F[j][a]]!=pos)
           { solve(F[j][a],k,a,b); //对之前状压结果为F[j][a]的情况考虑选或不选这个数的结果
             vis[F[j][a]]=pos;
           }
        }
        printf("%lld
    ",ans);
      }
    }



    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    Mysql-windows安装
    go-jwt生成token
    github下载慢的问题
    mysql主从复制(二)
    软件下载网站推荐
    Ubuntu14.04 安装ssh
    Ubuntu14.04 更换镜像源
    docker安装记录
    k8s安装记录
    Docker(一):Docker入门教程
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4688346.html
Copyright © 2011-2022 走看看