5429 多重背包
分析:
f[i]=g[j-k*siz[i]]+k*val[i];
发现一个状态d只会更新,d+siz[i],d+2*siz[i]...d+k*siz[i],所以可以枚举每个d,d<m,然后将d的倍数提出来(就是一个剩余系),然后这些状态就是随便转移了,然后单调队列优化。复杂度O(nm)。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline int read() { 17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 19 } 20 21 const int N = 7005; 22 23 int val[N], siz[N], cnt[N]; 24 int f[N], g[N], q[N]; 25 26 int main() { 27 int n = read(), m = read(); 28 for (int i=1; i<=n; ++i) { 29 siz[i] = read(), val[i] = read(), cnt[i] = read(); 30 } 31 for (int i=1; i<=n; ++i) { 32 for (int j=0; j<siz[i]; ++j) { 33 int L = 1, R = 0; 34 for (int k=0; j+k*siz[i]<=m; ++k) { 35 while (L <= R && q[L] < k - cnt[i]) L ++; 36 while (L <= R && f[j + q[R] * siz[i]] - q[R] * val[i] <= f[j + k * siz[i]] - k * val[i]) R --; 37 q[++R] = k; 38 g[j + k * siz[i]] = f[j + q[L] * siz[i]] - q[L] * val[i] + k * val[i]; 39 } 40 } 41 for (int i=1; i<=m; ++i) f[i] = g[i]; 42 } 43 printf("%d", f[m]); 44 return 0; 45 }