[HAOI2008]硬幣購物 題解
阿新 • • 發佈:2021-11-17
這題目我覺得很強的啊……
書歸正傳,這道題有一個顯然的多重揹包做法,但是很遺憾,這題過不去,時間複雜度是
那我們不妨先考慮一個簡單的東西,就是沒有硬幣數量的限制,那麼完全揹包就能秒了這個題
那有了限制之後呢?
那麼發現硬幣的數量只有4種,是個很好的性質
考慮容斥解決,對於第 \(j\) 個硬幣,其實他的答案就是拋掉多餘硬幣個數的,也就是題中的 \(d_j\)
實際上,我們應該拋掉 \(d_j +1\) 個的,因為可以不選,那麼就相當於減去 \(f[s-(d_j +1) \times c_j]\) ,答案就是 \(f[s]-f[s-(d_j +1) \times c_j]\)
如果算四個這玩意,就會算少,包括同時超過兩個限制條件的等等,因此,就可以容斥了,具體的大概就是奇數減,偶數加
程式碼如下
#include<bits/stdc++.h> const int N=100010; using namespace std; int T,c[10],d[10],s; long long ans=0,f[N]={1,0}; void bag(){for(int i=1;i<=4;i++) for(int j=c[i];j<=N-1;j++) f[j]+=f[j-c[i]];} void dfs(int x,int k,int sum){ if(sum<0) return ; if(x==5){ if(k&1) ans-=f[sum]; else ans+=f[sum]; return ; } dfs(x+1,k+1,sum-c[x]*(d[x]+1)),dfs(x+1,k,sum); } int main(){ scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&T); bag(); while(T-->0){ scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s); ans=0; dfs(1,0,s); printf("%lld\n",ans); } return 0; }