单调队列优化多重背包的板子。
我们朴素的多重背包做法是
的
可以用二进制优化成
更进一步的,我们可以用单调队列优化成
考虑转移方程
决策点不连续,怎么办呢
我们把j按mod v[i] 的余数分类,每一类重新标号,枚举余数d,那么有
其中
代表
就可以单调队列优化了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 210
#define M 20010
#define pa pair<int,int>
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,a[N],c[N],m,f[M];
pa q[M];
inline void Min(int &x,int y){if(y<x) x=y;}
int main(){
// freopen("a.in","r",stdin);
n=read();memset(f,inf,sizeof(f));f[0]=0;
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=n;++i) c[i]=read();m=read();
for(int i=1;i<=n;++i)
for(int j=0;j<a[i];++j){//divide by remainder
int qh=1,qt=0;
for(int k=0;;++k){
int x=k*a[i]+j;if(x>m) break;
while(qh<=qt&&k-q[qh].second>c[i]) ++qh;
while(qh<=qt&&f[x]-k<=q[qt].first) --qt;
q[++qt]=make_pair(f[x]-k,k);
Min(f[x],q[qh].first+k);
}
}
printf("%d\n",f[m]);
return 0;
}