题解 P2029 【跳舞】
一道不是十分水的
首先我们考虑
那么状态转移方程就出来了,我们把第一维改成本次跳到第
代码大概是这样
#include <cstdio>
#include <iostream>
#define MAXN 5010
using namespace std ; int i, j, k, Ans ;
int N, T, S[MAXN], dp[MAXN][MAXN], A[MAXN], B[MAXN] ;
int main(){
cin >> N >> T ;
for (i = 1 ; i <= N ; ++ i)
scanf("%d", &A[i]), S[i] = S[i - 1] + A[i] ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &B[i]) ;
for (i = 0 ; i <= N ; ++ i)
for (j = 0 ; j <= N ; ++ j)
dp[i][j] = -192608170 ; dp[0][0] = 0 ;
for (i = 1 ; i <= N ; ++ i)
for (j = 1 ; j <= i ; ++ j){
for (k = 0 ; k < i ; ++ k)
dp[i][j] = max(dp[i][j], dp[k][j - 1] - S[i - 1] + S[k] + A[i]) ;
if (j % T == 0) dp[i][j] += B[i] ; Ans = max(Ans, dp[i][j]) ;
}
cout << Ans << endl ; return 0 ;
}
但是我们发现,这个复杂度是
-
优化状态维数
-
优化转移复杂度
而此处我们不可以优化状态了,所以考虑优化转移复杂度。转移的复杂度是
从状态转移方程入手,我们发现有关于
此处笔者使用了比较玄学的存储方式……类似刷表……当然这个地方有多种的优化方式啦~
完整版
#include <cstdio>
#include <iostream>
#define MAXN 5010
using namespace std ; int i, j, k, p, Ans ;
int N, T, Last[MAXN], S[MAXN], dp[MAXN][MAXN], A[MAXN], B[MAXN] ;
int main(){
cin >> N >> T ;
for (i = 1 ; i <= N ; ++ i)
scanf("%d", &A[i]), S[i] = S[i - 1] + A[i] ;
for (i = 1 ; i <= N ; ++ i) scanf("%d", &B[i]) ;
for (i = 0 ; i <= N ; ++ i)
for (j = 0 ; j <= N ; ++ j)
dp[i][j] = -192608170 ; dp[0][0] = 0 ;
for (j = 1 ; j <= N ; ++ j){
for (i = j ; i <= N ; ++ i){
p = Last[i - j], Last[i - j] = 0 ;
dp[i][j] = p - S[i - 1] + A[i] ;
if (j % T == 0) dp[i][j] += B[i] ; Ans = max(Ans, dp[i][j]) ;
Last[i - j] = max(Last[i - j - 1], dp[i][j] + S[i]) ;
}
}
cout << Ans << endl ; return 0 ;
}
毒瘤常数优化后被艹到龟速的版本(1100ms +):
#include <cstdio>
#include <cstring>
#include <iostream>
#define max Max
#define MAXN 5010
#define Inf 19260817
using namespace std ; int i, j, k, p, t, Ans ;
int N, T, Last[MAXN], S[MAXN], dp[MAXN][MAXN], A[MAXN], B[MAXN] ;
inline int Max(int a, int b){
return a & ((b - a) >> 31) | b & ( ~ (b - a) >> 31) ;
}
inline int qr(){
int res = 0 ; char c = getchar() ;
while (!isdigit(c)) c = getchar() ;
while (isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar() ;
return res ;
}
int main(){
cin >> N >> T ;
for (i = 0 ; i <= N ; ++ i)
for (j = 0 ; j <= N ; ++ j)
dp[i][j] = -Inf ; dp[0][0] = 0 ;
for (i = 1 ; i <= N ; ++ i)
A[i] = qr(), S[i] = S[i - 1] + A[i] ;
for (i = 1 ; i <= N ; ++ i) B[i] = qr() ;
for (j = 1 ; j <= N ; ++ j){
for (i = j ; i <= N ; ++ i){
t = i - j, p = Last[t], dp[i][j] = p - S[i - 1] + A[i] ;
if (!(j % T)) dp[i][j] += B[i] ; Ans = max(Ans, dp[i][j]), Last[t] = max(Last[t - 1], dp[i][j] + S[i]) ;
}
}
cout << Ans << endl ; return 0 ;
}
唉,先有常数后有天,反向优化