题意:
地图为长为n个单位长度的直线,每通过一个单位长度需要t秒。
有3种塔,红塔可以在当前格子每秒造成x点伤害,绿塔可以在之后格子造成y点伤害,蓝塔可以使通过单位长度的时间增加z秒。
让你安排塔的排列是造成的伤害最大。
思路:
最开始想到dp,状态dp[i][r][g][b]表示:假设前i格放了r个红塔、g个绿塔和b个蓝塔,枚举第i+1格放什么。
因为长度最大为1500,所以如果这样开状态的话,需要1500^4的空间,这显然是开不下的。
后来想到,一种塔的数量可以表示成总数减去另外两种塔的数量,这样的话,就可以减掉一维,变成dp[i][g][b],还是会超空间。
然后想到,红塔只在当前格子有效,所以不用记录有多少红塔,只需要知道有多少绿塔和蓝塔就好了,也不用记录当前是第几格。所以状态变成了dp[g][b]。
但是,这样子时间复杂度仍然是n^3的,会超时。
可以证明,如果存在红塔,放在后面一定比放在前面更优。所以,只需要dp前面有g个绿塔和b个蓝塔时候造成的最大伤害,然后在求解的时候计算出后面全是红塔。 所以,时间复杂度也变成了n^2。这样子就可以解了。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <time.h> 15 16 using namespace std; 17 18 typedef __int64 ll; 19 20 const int INF = 1<<30; 21 const int MAXN = 1555; 22 23 ll dp[MAXN][MAXN]; //dp[i][j]: 前面i+j个塔中,有i个green,j个blue 24 ll n, x, y, z, t; 25 26 void solve() { 27 scanf("%I64d%I64d%I64d%I64d%I64d", &n, &x, &y, &z, &t); 28 29 memset(dp, 0, sizeof(dp)); 30 for (int i = 0; i < n; i++) 31 for (int j = 0; j+i < n; j++) { 32 dp[i+1][j] = max(dp[i+1][j], dp[i][j]+(i*y)*(t+j*z)); 33 dp[i][j+1] = max(dp[i][j+1], dp[i][j]+(i*y)*(t+j*z)); 34 } 35 36 ll ans = 0; 37 for (int i = 0; i <= n; i++) 38 for (int j = 0; i+j <= n; j++) 39 ans = max(ans, dp[i][j]+((n-i-j)*(x+i*y))*(t+z*j)); 40 41 printf("%I64d ", ans); 42 } 43 44 int main() { 45 #ifdef Phantom01 46 freopen("HDU4939.txt", "r", stdin); 47 #endif //Phantom01 48 49 int T; 50 scanf("%d", &T); 51 for (int i = 1; i <= T; i++) { 52 printf("Case #%d: ", i); 53 solve(); 54 } 55 56 return 0; 57 }