Codevs P1997 守衛者的挑戰
題目描述 Description
打開了黑魔法師Vani的大門,隊員們在迷宮般的路上漫無目的地搜尋着關押applepi的監獄的所在地。突然,眼前一道亮光閃過。“我,Nizem,是黑魔法聖殿的守衛者。如果你能通過我的挑戰,那麼你可以帶走黑魔法聖殿的地圖……”瞬間,隊員們被傳送到了一個擂臺上,最初身邊有一個容量爲K的包包。
擂臺賽一共有項挑戰,各項挑戰依次進行。第項挑戰有一個屬性ai,如果ai≥0,表示這次挑戰成功後可以再獲得一個容量爲ai的包包;如果ai = -1,則表示這次挑戰成功後可以得到一個大小爲 1 的地圖殘片。地圖殘片必須裝在包包裏才能帶出擂臺,包包沒有必要全部裝滿,但是隊員們必須把獲得的所有的地圖殘片都帶走(沒有得到的不用考慮,只需要完成所有N項挑戰後揹包容量足夠容納地圖殘片即可),才能拼出完整的地圖。並且他們至少要挑戰成功L次才能離開擂臺。
隊員們一籌莫展之時,善良的守衛者Nizem幫忙預估出了每項挑戰成功的概率,其中第i項挑戰成功的概率爲pi %。現在,請你幫忙預測一下,隊員們能夠帶上他們獲得的地圖殘片離開擂臺的概率。
輸入輸出 Input&Output
輸入描述 Input Description
第一行三個整數N,L,K。
第二行N個實數,第i個實數pi表示第i項挑戰成功的百分比。
第三行N個整數,第i個整數ai表示第i項挑戰的屬性值。
輸出描述 Output Description
一個整數,表示所求概率,強制四捨五入保留6位小數。
樣例 Sample
樣例輸入 Sample Input
【樣例輸入1】
3 1 0
10 20 30
-1 -1 2
【樣例輸入2】
5 1 2
36 44 13 83 63
-1 2 -1 2 1
樣例輸出 Sample Output
【樣例輸出1】
0.300000
【樣例輸出2】
0.980387
數據範圍及提示 Data Size & Hint
在第一個樣例中,若第三項挑戰成功,如果前兩場中某場勝利,隊員們就有空間來容納得到的地圖殘片,如果挑戰失敗,根本就沒有獲得地圖殘片,不用考慮是否能裝下;若第三項挑戰失敗,如果前兩場有勝利,沒有包來裝地圖殘片,如果前兩場都失敗,不滿足至少挑戰成功L次(L = 1)的要求。因此所求概率就是第三場挑戰獲勝的概率。
對於 100% 的數據,保證0≤K≤2000,0≤N≤200,-1≤ai≤1000,0≤L≤N,0≤pi≤100。
來源:Nescafe 17
分析
先將獎賞按從大到小排列,這樣搜到時如果揹包體積>0則是可行的<0則不可行。因爲已經按照從大到小排序,獲得的揹包早就獲得完畢,再出現負值肯定不能再有包裝進去。
設f[i,j,k]表示前i場中贏j場容量爲k的概率
那麼f[i+1,j,k]:=f[i+1,j,k]f[i,j,k]*(1-p[i+1]) 累加上第i+1場未獲勝的概率
如果第i+1場獲勝那麼得到num[i+1]的揹包或地圖,所以i+1場勝利時容量爲k+num[i+1],當小於0時無意義,表示揹包不夠。
所以如果k+num[i+1]>0和n取較小值,大於n沒有用處。
所以當第i+1場勝利時
now:=k+num[i+1]
now:=min(now,n);
f[i+1,j+1,now]:=f[i+1,j+1,now]+f[i,j,k]*p[i+1];
最終答案就是打完n場後勝利l場以上的揹包容量>=0的概率和。>=0表示地圖已全部被裝下。
代碼如下
program p1997;
var now,n,l,k,i,j,s,e:longint;
p:array[1..1000] of double;
num:array[1..1000] of integer;
f:array[0..200,0..200,0..200] of double;
ans:double;
function min(a,b:longint):longint;
begin
if a<b then exit(a);
exit(b);
end;
procedure qsort(l,r:longint);
var i,j,mid:longint;
temp1:longint;
temp2:double;
begin
i:=l;
j:=r;
mid:=num[(i+j)>>1];
while i<=j do
begin
while num[i]>mid do inc(i);
while num[j]<mid do dec(j);
if i<=j
then
begin
temp1:=num[i];
temp2:=p[i];
num[i]:=num[j];
p[i]:=p[j];
num[j]:=temp1;
p[j]:=temp2;
inc(i);
dec(j);
end;
end;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
begin
readln(n,l,k);
for i:=1 to n do
begin
read(p[i]);
p[i]:=p[i]/100;
end;
for i:=1 to n do
read(num[i]);
qsort(1,n);
f[0,0,min(k,n)]:=1;
for i:=0 to n-1 do
for j:=0 to i do
for s:=0 to n do
begin
f[i+1,j,s]:=f[i+1,j,s]+f[i,j,s]*(1-p[i+1]);
now:=s+num[i+1];
if now<0 then continue;
now:=min(now,n);
f[i+1,j+1,now]:=f[i+1,j+1,now]+f[i,j,s]*(p[i+1]);
end;
for i:=0 to n do
for j:=l to n do
ans:=ans+f[n,j,i];
write(ans:0:6);
end.
評測結果
測試點#guard1.in 結果:AC 內存使用量: 256kB 時間使用量: 0ms
測試點#guard10.in 結果:AC 內存使用量: 32880kB 時間使用量: 102ms
測試點#guard2.in 結果:AC 內存使用量: 368kB 時間使用量: 0ms
測試點#guard3.in 結果:AC 內存使用量: 256kB 時間使用量: 0ms
測試點#guard4.in 結果:AC 內存使用量: 1136kB 時間使用量: 0ms
測試點#guard5.in 結果:AC 內存使用量: 1264kB 時間使用量: 1ms
測試點#guard6.in 結果:AC 內存使用量: 2412kB 時間使用量: 4ms
測試點#guard7.in 結果:AC 內存使用量: 8556kB 時間使用量: 17ms
測試點#guard8.in 結果:AC 內存使用量: 8556kB 時間使用量: 18ms
測試點#guard9.in 結果:AC 內存使用量: 18800kB 時間使用量: 48ms