zoukankan      html  css  js  c++  java
  • bzoj1190 [HNOI2007]梦幻岛宝珠

    传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1190

    【题解】

    首先,我们把所有物品都分解成$a imes 2^b$的形式,然后把物品按照$b$分组;

    我们按$b$从高到低考虑。$f(i,j)$表示考虑到$2^i$,当前还剩余$j imes 2^i$的空间,所能取到的最大值。

    每层先从上一层传递$f$数组,然后再更新。每次就是一个背包转移了。

    考虑这个$j$可能随着$b$减小越来越大,我们需要优化。

    对于每一层的物品,最多只能表示成$na imes 2^b$的形式,即最多$1000 imes 2^b$。

    所以对于上一层传下来的值,如果它乘了2之后大于1000,实际上这些多于1000的部分是没有用的,我们可以直接舍弃!

    这样的话就能保证复杂度了!

    # include <vector>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int M = 5e5 + 10;
    const int mod = 1e9 + 7;
    
    int n, W; 
    
    vector<int> w[32], v[32];
    ll f[32][1010];
    int to[32];
    
    bool Main() {
      cin >> n >> W;
      if(n == -1 && W == -1) return 0;
      for (int j=0; j<=31; ++j) {
        w[j].clear(), v[j].clear(), to[j] = 0;
        for (int i=0; i<=1000; ++i) f[j][i] = 0;
      } 
      for (int j=1; j<=n; ++j) {
        int ww, vv;
        cin >> ww >> vv;
        for (int i=30; ~i; --i) {
          if(ww % (1 << i) == 0) {
            w[i].push_back(ww / (1 << i));
            v[i].push_back(vv);
            break;
          }
        }
      }
      
      
      for (int j=30, curW=0; ~j; --j) {
        bool flag = 0;
        to[j] = to[j+1] * 2;
        if(W & (1<<j)) flag = 1, to[j] ++;
        
        if(to[j] <= 1000) {
          for (int i=0; i<=to[j]; ++i) 
            if(flag == 0) {
              if(i%2 == 0) f[j][i] = f[j+1][i/2];
            } else if(i%2 == 1) f[j][i] = f[j+1][i/2];
        } else {
          for (int i=0; i<=1000; ++i) 
            if(flag == 0) {
              if(i%2 == 0) f[j][i] = f[j+1][i/2];
            } else if(i%2 == 1) f[j][i] = f[j+1][i/2];
          for (int i=500; i<=to[j+1]; ++i)
            f[j][1000] = max(f[j][1000], f[j+1][i]); 
          to[j] = 1000;
        }
        
        
        for (int k=0, kto = w[j].size(); k<kto; ++k) {
          for (int i=0; i<=to[j]; ++i) {
            int tw = w[j][k], tv = v[j][k];
            if(i - tw >= 0) f[j][i-tw] = max(f[j][i-tw], f[j][i]+tv);
          }
        }
        
      }
      
      ll ans = 0;
      for (int i=to[0]; ~i; --i) ans = max(ans, f[0][i]);
      cout << ans << endl; 
      return 1;
    }
    
    int main() {
      while(Main());
      return 0;
    }
    View Code

     

  • 相关阅读:
    css的书写位置+元素分类
    选择器
    我的js运动库新
    js的相关距离
    关于小乌龟的使用
    linux 基础
    linux shell快捷操作【超级实用】
    算法面试常见问题【转】
    http://www.cnblogs.com/zhangchaoyang/archive/2012/08/28/2660929.html
    cocos2dx + vs安装使用
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj1190.html
Copyright © 2011-2022 走看看