[BZOJ1042]AOI2008]硬幣購物
阿新 • • 發佈:2018-03-08
names stream 是我 logs 並不是 輸出 總結 cst isdigit
表示不考慮任何限制,由四種硬幣組成價值為i的方案數,轉移為:$f[i]=\sum {f_{i-c_j}} (j \leq 4) $
顯然這並不是最後的答案,因為這些方案裏還藏著不少幾類硬幣超限的方案,於是我們需要用容斥原理把他們減掉
ans=\(f_s\) -(只有第一類硬幣超的方案)--(只有第二類硬幣超的方案)-(只有第三類硬幣超的方案)-(只有第四類硬幣超的方案)+(只有第一類第二類硬幣超的方案)+..+
反正就是這四個集合的交加加減減
現在考慮如何算(只有第一類硬幣超的方案)。當第一類硬幣去到\(d_1+1\) 時那麽一定就超了,剩下的空間就可以隨便分配了,所以這個方案數$ =f_{s-c_1*(d_1+1)}$
其他的都類似。
題目描述 Description
硬幣購物一共有4種硬幣。面值分別為\(c_1\) ,\(c_2\) ,\(c_3\) ,\(c_4\) 。某人去商店買東西,去了\(tot\) 次。每次帶\(d_i\) 枚\(c_i\) 硬幣,買\(s_i\) 的價值的東西。請問每次有多少種付款方法。
輸入描述 Input Description
第一行 \(c_1\) ,\(c_2\) ,\(c_3\) ,\(c_4\) ,\(tot\) 下面\(tot\) 行 \(d_1\) ,\(d_2\) ,\(d_3\) ,\(d_4\) ,\(s\) ,
輸出描述 Output Description
每次的方法數
樣例輸入 Sample Input
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900
樣例輸出 Sample Output
4
27
數據範圍及提示 Data Size & Hint
其中\(d_i,s<=100000,tot<=1000\)
之前的一些廢話
退役的我回歸了,但這次重返只是為了明天的比賽,時間雖短,但重新拾起這一切的我找到了5個月前為了夢想奮鬥的自己,當時的自己熱血沸騰,充滿鬥誌,說真的,我無比熱愛這種感覺,但這畢竟只是曇花一現,轉瞬即逝的。
題解
背包問題帶有這麽多附屬條件,還有數量限制,看起來好復雜啊。(誰叫我幾個月沒有碰OI,大腦生銹了呢)
但是如果不考慮數量限制,這就是一個很智障的背包問題了(md第一次打我循環順序還打反了)
\(f_i\)
顯然這並不是最後的答案,因為這些方案裏還藏著不少幾類硬幣超限的方案,於是我們需要用容斥原理把他們減掉
ans=\(f_s\) -(只有第一類硬幣超的方案)--(只有第二類硬幣超的方案)-(只有第三類硬幣超的方案)-(只有第四類硬幣超的方案)+(只有第一類第二類硬幣超的方案)+..+
反正就是這四個集合的交加加減減
現在考慮如何算(只有第一類硬幣超的方案)。當第一類硬幣去到\(d_1+1\) 時那麽一定就超了,剩下的空間就可以隨便分配了,所以這個方案數$ =f_{s-c_1*(d_1+1)}$
其他的都類似。
代碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstdlib>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c==‘-‘)f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();}
return x*f;
}
const int maxn=5;
int c[maxn],d[maxn];
LL dp[100010];
int main()
{
for(int i=0;i<4;i++)c[i]=read();
dp[0]=1ll;
for(int i=0;i<4;i++)
for(int j=c[i];j<=100000;j++)dp[j]+=dp[j-c[i]];
//for(int i=0;i<=10;i++)printf("DP:%d %d\n",i,dp[i]);
//cout<<"fa"<<dp[100000]<<endl;
int T=read();
while(T--)
{
for(int i=0;i<4;i++)d[i]=read();
int s=read();
LL ans=0;
for(int i=0;i<16;i++)
{
int cnt=0;
LL tmp=0;
for(int j=0;j<4;j++)
if(i&(1<<j))cnt++,tmp+=(LL)c[j]*(LL)(d[j]+1);
if(tmp>s)continue;
if(cnt%2)ans-=dp[s-tmp];
else ans+=dp[s-tmp];
}
printf("%lld\n",ans);
}
return 0;
}
總結
大腦不再那麽銹了
[BZOJ1042]AOI2008]硬幣購物