<> 예
<첫 번째 업데이트>
<텍스트>
최적화
기술
\ (\ _world의 \를 방문) 몇 가지 최적화 문제는 매우 통상의 지식을 해결할 수 있습니다 발견, 그래서 그는 당신이 그런 질문을 공유했다 :
이제 정수 N의 시퀀스 길이가 \을 (\ {A_I \} \) , 당신은 (존재하는 요소에서 선택할 수 없습니다)이 분리 된 K 연속 하위 간격을 선택해야하고, 그들이 기억하는에서 왼쪽에서 오른쪽으로 \ (S1, S2, ..., SK \)를 . 우리의 목표는 최적화하고 다음과 같은 공식을 극대화하는 것입니다 :
\ [\ sum_ I = {1} ^ K | s_i-S_ {I + 1} | \]
당신은 가장 큰 출력을 필요로 할 수있다.
입력 형식
두 정수 N, K의 첫 번째 라인은, 상기와 같이 의미한다.
다음 라인 N 정수, i 번째의 AI를 나타내고, 확인 (^ \ ≦ 제 4 | | A_I) \를 .
출력 형식
출력 라인 답을 나타내는 정수입니다.
샘플 입력
5 3
5 2 4 3 1
샘플 출력
12
결심
아주 마법 \ (DP \) .
절대 최대 약간 정보 \ (트릭 \) , 오픈 양극 및 음극 모두의 경우의 수의 절대 값 \ (DP의 \)은 , 최종적으로 소정의 최대 최적의 솔루션이다.
那么我们发现对于一个\(s_i\),他可能有三种贡献系数:\(2,-2,0\),这与\(s_{i-1},s_{i+1}\)与其的相对大小关系有关,当然,对于\(s_1,s_k\),他们的贡献系数还有可能是\(1,-1\),我们不妨由此设计状态。
设\(f[i][j][0/1/2/3]\)代表前\(i\)个数,分成\(j\)段,当前处于最大值(\(+2\)贡献),最小值(\(-2\)贡献),上升状态(\(0\)贡献),下降状态(\(0\)贡献)的最大和。其中上升状态和下降状态指的就是最大值和最小值前的一些\(0\)贡献的状态。
然后就可以\(dp\)了,时间复杂度是\(O(n^3k)\)的。
考虑优化,第一个就是我们可以强制认为每一个数字都是要取的,当然不取可以放在\(0\)贡献的状态里处理。第二个每一段当中的数字贡献系数的相同的,可以直接一个一个添加数字。
\(Code:\)
#include <bits/stdc++.h>
using namespace std;
const int N = 3e4+20 , K = 220 , INF = 0x3f3f3f3f;
inline int read(void)
{
int x = 0 , w = 0; char ch = ' ';
while ( !isdigit(ch) ) w |= ch == '-' , ch = getchar();
while ( isdigit(ch) ) x = x * 10 + ch - 48 , ch = getchar();
return w ? -x : x;
}
int n,k,a[N],f[N][K][4];
inline void input(void)
{
n = read() , k = read();
for (int i=1;i<=n;i++)
a[i] = read();
}
inline void dp(void)
{
memset( f , 0xcf , sizeof f );
for (int i=1;i<=n;i++)
f[i][0][0] = f[i][0][1] = f[i][0][2] = f[i][0][3] = 0;
f[0][0][0] = f[0][0][1] = f[0][0][2] = f[0][0][3] = 0;
for (int i=1;i<=n;i++)
for (int j=1;j<=min(i,k);j++)
{
int mul = 2;
if ( j == 1 || j == k ) mul--;
f[i][j][0] = max( f[i-1][j][0] , f[i-1][j-1][2] ) + mul * a[i];
f[i][j][1] = max( f[i-1][j][1] , f[i-1][j-1][3] ) - mul * a[i];
f[i][j][2] = max( f[i-1][j][2] , f[i][j][1] );
f[i][j][3] = max( f[i-1][j][3] , f[i][j][0] );
if ( mul == 1 ) continue;
f[i][j][2] = max( f[i][j][2] , f[i-1][j-1][2] );
f[i][j][3] = max( f[i][j][3] , f[i-1][j-1][3] );
}
}
int main(void)
{
input();
dp();
printf("%d\n",max(f[n][k][2],f[n][k][3]));
return 0;
}
<后记>