失蹤oj回歸。
小c通過這道題mark一下容斥一類的問題。
硬幣購物一共有4種硬幣。面值分別為c1,c2,c3,c4。某人去商店買東西,去了tot次。每次帶di枚ci硬幣,買s的價值的東西。請問每次有多少種付款方法。
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s。
每次的方法數。
1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900427
di,s<=100000,tot<=1000。
o(s*tot)的dp演算法誰都會寫,但是看著這時間複雜度你難道不虛嗎?
你難道甘願被卡常而就此丟掉10分或是在刷題時打乙個這樣的暴力草草了事而對其中的精妙不聞不問,你的良心不會痛嗎?
如果你在解題時看到題目中有常數a(a<20)這樣的資料,不妨就往o(2a)這樣複雜度的演算法去想一想。
因為題目中有乙個常數4,而且還都是限制條件,所以我們就往狀壓、容斥這方面去想。
顯然狀壓是不可能的,於是我們就只有容斥了。
首先我們要知道容斥在這道題是幹嘛用的:
容斥就是對多個限制條件下方案的去重工作,也就是你們所熟知的,求多個集合的並集。
容斥常常伴隨的思想是一種逆向思維,就是題目往往要求我們去求多個集合的交,然而我們並沒有好的辦法,轉而跑去求各個集合的補的並,再補回來就是各個集合的交。
我們需要理解在這個演算法中, 交 是可以o(1)求得的,然而 並 需要用容斥求得。
所以解這樣的題目的大致思路就是:
題目要求我們求a1~an的交,但是我們發現很難求;
所以我們去求cua1~cuan的並,而cua1~cuan的並需要我們求cua1~cuan的交,但是我們發現cua1~cuan的交特別好求,所以我們就圓滿地解決了這個問題。
運用這樣的思路,我們就可以很快解出這道題。
所以我們要求的只剩,在這次購物中,第 i 種硬幣用了超過di的方案數。
腦補一下,我們就知道,我們只要每種硬幣先取到它們限制的數量+1,剩下隨便取就可以了,這樣的方案無論如何都是滿足每種硬幣都超過限制的。
所以用一句話概括題解:容斥,求f[s-σ(ci*(di+1))],f[x]為在沒有任何限制下,取硬幣得到面值x的方案數。
時間複雜度o(max(s)*4+tot*16)。注意答案最大為c(s,4)會爆int。
#include #include#include
#define ll long long
#define mm 100005
using
namespace
std;
intn,m;
int a[5],g[5],ys[5
];ll f[mm],lt,ans;
bool
u;inline
intread()
while (c>='
0' && c<='
9')
return n*f;
}int
main()
printf(
"%lld\n
",ans);
}}
大概就是小c關於容斥的一點點想法,當然這樣的題目還有很多無法以偏概全。希望這樣的思路能對以後有一點幫助吧。
BZOJ 1042 硬幣購物
1042 haoi2008 硬幣購物 time limit 10 sec memory limit 162 mb description 硬幣購物一共有4種硬幣。面值分別為c1,c2,c3,c4。某人去商店買東西,去了tot次。每次帶di枚ci硬幣,買s i的價值的東西。請問每次有多少種付款方法。i...
BZOJ 1042 硬幣購物
dp 容斥原理。我們先預處理出無限制 無限 揹包的情況 然後answer就是全部無限制的情況總數減去某個物品超過限制的情況總數。設0000為全部無限制的情況,0101為c2,c4超過限制 其餘無限制 的情況總數,其他的同理。則answer 0000 0001 0010 0100 1000 1100 ...
BZOJ 1042 硬幣購物 (數論 容斥)
time limit 10 sec memory limit 162 mb description 硬幣購物一共有4種硬幣。面值分別為c1,c2,c3,c4。某人去商店買東西,去了tot次。每次帶di枚ci硬幣,買s i的價值的東西。請問每次有多少種付款方法。input 第一行 c1,c2,c3,c...