丟一道利用調整思想解的好題
【題目描述】
long long ago,D國受到了一條惡龍的襲擊,爲了保衛人民的生命財產安全,D國第一勇士盾盾挺身而出,與這條惡龍決一死戰。
這個戰鬥的過程可以看成由n個回合組成,對於每一個回合,盾盾先行動,惡龍再行動。戰鬥一開始時,盾盾有A點血,惡龍有B點血。
盾盾有3個技能:
ATTACK:盾盾會向惡龍發起進攻,對惡龍造成X點傷害
DEFEND:盾盾該回合能處於絕對防禦狀態,這回閤中惡龍無法對盾盾造成傷害
HEAL:盾盾能瞬間恢復Y點血
而惡龍每一回合都只會向盾盾直接發起進攻,第i回合造成的傷害爲ci。一旦盾盾或是惡龍的血量小於或等於0了,他就會立即死亡。
可以看出,這場殊死搏鬥中,盾盾與惡龍對戰的策略是非常重要的,所以你需要幫盾盾設計一個最優的方案:如果盾盾能在n回合內戰勝惡龍,你就要找出最少的回合;而如果無論如何盾盾都不能在n回合內戰勝惡龍(盾盾是可能戰死沙場的),你就需要算出盾盾能對惡龍造成的最大傷害值。
【輸入數據】
第一行爲5個數,分別爲n,X,Y,A,B,意義見描述
接下來n行,每行1個數ci,意義見描述
【輸出數據】
包括兩行
如果能戰勝惡龍,則第一行輸出“Win”,第二行輸出戰勝惡龍花費的最少的回合數
如果無論如何都不能在n回合內戰勝,則在第一行輸出“Lose”,第二行輸出能盾盾對惡龍造成的最大傷害值
【輸入樣例1】
4 1 1 3 3
1
10
1
10
【輸出樣例1】
Win
4
【輸入樣例2】
4 1 1000 1 4
1
10
1
1
【輸出樣例2】
Lose
3
【數據約定】
對於50%的數據,n<=10000,A,B<=5000,ci,X,Y<=200
對於100%的數據,n<=100000,A,B<=1000000000,ci,X,Y<=10000
正解是greedy + heap 時間複雜度O(nlogn)
直接貼題解吧
由於要對龍造成最大傷害,所以我們要不必對自己的剩餘血量太擔心,先全力向惡龍進攻。而如果你還沒把龍弄死你就掛了,這個時候我們其實是可以讓“時光倒流”的——主動權在我們手上不是?這個時候我們就需要考慮要抵消之前的某一些回合的傷害直到讓自己復活才行,比方說對於之前的第i回合,我們不去Attack惡龍了,改爲進行防禦性操作,我們能defend掉龍噴我們的a[i]點血,或是heal自己Y點血,而顯然在要這兩者之中選個大的作爲我們的選擇。如果我們到了第i回合後,自身血量小於或等於0了,我們就需要在之前的所有回合中選一個能回最多血的回合,然後讓“時光倒流”,讓我們的勇士在那個回合改爲做相應的回覆操作,如此重複直到血量大於0,而這個取最大值的操作可以用堆來實現。綜上,我們就可以這樣得到答案了。(By SYJ)
然後是代碼(其實我發此文主要意義在此)
經過我自己小小的縮行 + LYP的神奇般的超級大縮行後(PAS止步吧)
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 100000 + 5;
struct Heap { int data; };
int n, X, Y, A, B, flood, Maxat;
int c[maxn], cost;
int tot;
Heap heap[maxn];
int Max(int a, int b) { return a > b ? a : b; }
void Swap(Heap &x, Heap &y) { Heap t = x; x = y; y = t; }
void Up(int p)
{
for (; (p >> 1) && heap[p >> 1].data < heap[p].data; Swap(heap[p >> 1], heap[p]), p >>= 1);
}
void Down(int p)
{
while (p << 1 <= tot)
if (p << 1 < tot)
{
int q = heap[p << 1].data > heap[p << 1 | 1].data ? p << 1 : p << 1 | 1;
if (heap[p].data < heap[q].data)
Swap(heap[p], heap[q]), p = q; else break;
}
else if (p << 1 == tot)
{
if (heap[p << 1].data > heap[p].data)
Swap(heap[p << 1], heap[p]);
break;
}
}
void Insert(int data)
{
heap[++tot].data = Max(Y, data);
Up(tot);
}
void Getpop()
{
int MAX = heap[1].data;
heap[1] = heap[tot--];
Down(1);
A += MAX; B += X;
}
void Win(int i)
{
cout << "Win" << endl
<< i << endl;
exit(0);
}
void Lose()
{
cout << "Lose" << endl
<< flood - Maxat << endl;
}
int main()
{
freopen("fight.in", "r", stdin);
freopen("fight.out", "w", stdout);
cin >> n >> X >> Y >> A >> B;
flood = Maxat = B;
for (int i = 1; i <= n; ++i)
scanf("%d", &c[i]);
for (int i = 1; i <= n; ++i)
{
B -= X; Insert(c[i]);
B < Maxat && (Maxat = B) <= 0 ? Win(i) : (void)0;
for (A -= c[i]; A <= 0; Getpop())
if (!tot) return Lose (), 0;
}
Lose();
return 0;
}
還要感謝DRJ,與SYJ的堆代碼,終於把以前的大常數maintain堆改了