連結:http://acm.hdu.edu.cn/showproblem.php?pid=3646
題意:你有N把武器,每把武器可以對敵人造成一定的傷害(et:攻擊力500,敵人血量為200,殺死敵人,攻擊力剩餘300),一共有K個敵人,你有M次魔法double武器的攻擊力(加倍),使用武器是有規則的:武器有兩個狀態,一個狀態為young,一個為old,新的武器狀態為young,當你用它殺死一個敵人之後,狀態變為old,當狀態為young的時候,即使該武器剩餘的攻擊力不足以殺死當前的敵人,但是可以傷害他一定血量,但是為old的時候,武器攻擊力不足以殺死對方,就無法攻擊他(比如攻擊力為200,敵人血量500,young:敵人減少200,old:敵人血量不減)。使用武器的順序和殺人的順序是給定的。問你最多能殺死幾個人?
見解:如果沒有old,young的話,這是一個水DP,有了這個狀態的話,我們不好處理,主要是不知道當前武器的狀態是什麼,如果加一維表示目前狀態的話,那麼還得再來一維表示正在挑戰第幾個敵人,我們可以這樣理解狀態,dp【i】【j】表示使用完了i把武器,用了j次魔法,一共造成的傷害是多少,轉移的時候,二分下現在的傷害就能知道現在在殺第a個人,然後二分再使用一把武器的造成的傷害,能知道挑戰到第b個人,如果兩個人不是同一個人,那說明我們無法傷害b,那麼使用這把武器後我們能造成的傷害就是sum【b】了,最後二分傷害,就可以知道最多殺死幾個人了,詳細看代碼:
#include<stdio.h>#include<string.h>#include<algorithm>#define Max(a,b) ((a)>(b)?(a):(b))using namespace std;const int maxn = 105;const int maxm = 100005;int dp[2][maxn],life[maxm],power[maxn * maxn],N,M,K;int sum[maxm];int main(){ int cnt = 0; while(scanf("%d%d%d",&N,&M,&K) && N + M + K) { for(int i = 1;i <= N;i ++) scanf("%d",&power[i]); for(int i = 1;i <= K;i ++) { scanf("%d",&life[i]); sum[i] = sum[i - 1] + life[i]; } int ans = 0; M = min(M,N); memset(dp,0,sizeof(dp)); for(int i = 1;i <= N && !ans;i ++) { for(int j = 0;j <= M;j ++) { int a , b, next_a,next_b; a = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j]) - sum;// now killed if(j) { b = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j - 1]) - sum;//now killed j - 1 next_b = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j - 1] + (power[i] << 1)) - sum;// use power } next_a = upper_bound(sum + 1,sum + 1 + K,dp[(i - 1) & 1][j] + power[i]) - sum;//not use power int hurt_a = dp[(i - 1) & 1][j] + power[i],hurt_b ; if(a != next_a) hurt_a = sum[next_a - 1]; if(j) hurt_b = dp[(i - 1) & 1][j - 1] + (power[i] << 1); if(j) if(b != next_b) hurt_b = sum[next_b - 1]; if(j)dp[i & 1][j] = Max(hurt_a,hurt_b); else dp[i & 1][j] = hurt_a; if(dp[i & 1][j] >= sum[K]) { ans = K; break; } } } if(!ans) ans = upper_bound(sum + 1,sum + 1 + K,dp[N & 1][M]) - sum - 1; printf("%d\n",ans); } return 0;}