poj1742 Coins
阿新 • • 發佈:2019-01-02
題解:
這是個多重揹包,但是一般的複雜度是過不去這題的。
所以有二進位制優化和單調佇列優化。
二進位制優化是將數量$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> usingnamespace 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; }