标签:std using scan ble mes += ref for algorithm
题解:
这是个多重背包,但是一般的复杂度是过不去这题的。
所以有二进制优化和单调队列优化。
二进制优化是将数量$n$化为多个数,而且这些数能表示出$1~n$中的任意数。
怎么保证?
想起二进制,我们可以将$n$分为$1+2+4+8+……+k$,$k$可以是任意数。
单调队列怎么优化?
我们发现,转移时$f[i]$的状态可由$f[i-a*k]$转移而来,于是对于$0~a-1$进行枚举,每次更新与之同余的所有数。
单调队列代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 105 #define M 100050 int n,m,a[N],c[N]; bool f[M]; int sta[M],hd,tl; int main() { while(scanf("%d%d",&n,&m)) { if(!n&&!m)break; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&c[i]); memset(f,0,sizeof(f)); f[0]=1; for(int i=1;i<=n;i++) { if(c[i]==1) { for(int j=m;j>=a[i];j--) if(f[j-a[i]])f[j]=1; }else if(a[i]*c[i]>=m) { for(int j=a[i];j<=m;j++) if(f[j-a[i]])f[j]=1; }else { for(int j=0;j<a[i];j++) { hd=1,tl=0; for(int k=j;k<=m;k+=a[i]) { while(hd<=tl&&sta[hd]+c[i]*a[i]<k)hd++; if(!f[k]) { if(hd<=tl)f[k]=f[sta[hd]]; }else { sta[++tl]=k; } } } } } int ans = 0; for(int i=1;i<=m;i++)ans+=f[i]; printf("%d\n",ans); } return 0; }
标签:std using scan ble mes += ref for algorithm
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10206818.html