bzoj1190 [HNOI2007]梦幻岛宝珠

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

【题解】

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

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

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

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

对于每一层的物品,最多只能表示成$na\times 2^b$的形式,即最多$1000 \times 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

 

posted @ 2019-02-14 20:43  Galaxies  阅读(487)  评论(0编辑  收藏  举报