迎春舞會之三人組舞——dp
阿新 • • 發佈:2019-01-12
文章目錄
題目
初看此題,難免想起這道題目
但仔細想想,發現中間那個人的標記會很難搞
於是便有了如下思路
思路
dp[i][j]表示在前i個人中分成j組的最小殘疾程度
便有如下狀態轉移方程
dp[i][j] = min(dp[i-1][j],dp[i-2][j-1]+(num[i]-num[i-1])^2)
但有以下要點
當i - 1 >= j * 3
時
dp[i-1][j]
才合法
但中間那個怎麼確定前 i 箇中一定存在一個沒用過且比方程中的
num[i]&&num[i-1]
高呢?
就有如下技巧
讀入時
for(i = 1;i <= n;i++)
Read(num[n - i + 1]);
題目說了保證升序
這樣讀入保證了降序
迴圈時
for(i = 3;i <= n;i++)
{
for(j = 1;j <= i / 3;j++)
{
//j * 3 <= i的,那麼在前i個當中一定存在一個比num[i],num[i - 1]大的
//因為num[i],num[i - 1]是前i箇中最小的
dp[i][j] = dp[i - 2][j - 1] + M(num[i] - num[i - 1]);
dp[i][j] = Min(dp[i][j],i - 1 >= j * 3?dp[i - 1][j]:0x7f7f7f);
}
}
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define M(x) (x) * (x)
using namespace std;
const int MAXN = 5001;
template<typename T>
inline void Read(T &x)
{
char a = getchar();
bool f = 0;
x = 0;
while(a > '9'||a < '0') {if(a == '-') f = 1;a = getchar();}
while(a >= '0'&&a <= '9') {x = x * 10 + a - '0';a = getchar();}
if(f) x *= -1;
}
template<typename T>
inline T Min(T a,T b) {if(a < b) return a;return b;}
int num[MAXN];
int dp[MAXN][1001];
int main()
{
int n,m,i,j;
Read(m),Read(n);
for(i = 1;i <= n;i++)
Read(num[n - i + 1]);
for(i = 3;i <= n;i++)
{
for(j = 1;j <= i / 3;j++)
{
dp[i][j] = dp[i - 2][j - 1] + M(num[i] - num[i - 1]);
dp[i][j] = Min(dp[i][j],i - 1 >= j * 3?dp[i - 1][j]:0x7f7f7f);
}
}
printf("%d",dp[n][m]);
}