[noi707]LP
(以下用$Sa=\sum_{j=1}^{i}xi\cdot ai$,Sb和Sc同理)
令f[i][x]表示前i个数,$Sa\le x\le Sb$时最小的Sc
考虑第i个数是否选择,可以得到递推式$f[i][x]=min(f[i-1][x],min(f[i-1][x-j])+ci)$(j满足$ai\le j\le bi$),这个东西用单调队列维护即可
(这个转移的正确性可以用充分和必要两方面来考虑,具体不证了)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1005 4 #define oo 0x3f3f3f3f 5 int t,n,m,l,r,a[N],b[N],c[N],q[N*10],f[N][N*10]; 6 int main(){ 7 scanf("%d",&t); 8 while (t--){ 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 11 for(int i=1;i<=n;i++)scanf("%d",&b[i]); 12 for(int i=1;i<=n;i++)scanf("%d",&c[i]); 13 for(int i=1;i<=m;i++)f[0][i]=oo; 14 f[0][0]=0; 15 for(int i=1;i<=n;i++){ 16 l=1; 17 r=0; 18 for(int j=0;j<=m;j++){ 19 if (a[i]<=j){ 20 while ((l<=r)&&(f[i-1][j]<=f[i-1][q[r]]))r--; 21 q[++r]=j-a[i]; 22 } 23 while ((l<=r)&&(q[l]<j-b[i]))l++; 24 f[i][j]=f[i-1][j]; 25 if (l<=r)f[i][j]=min(f[i][j],f[i-1][q[l]]+c[i]); 26 } 27 } 28 if (f[n][m]==oo)printf("IMPOSSIBLE!!!\n"); 29 else printf("%d\n",f[n][m]); 30 } 31 }