【Codeforces 571B】Minimization 思維dp

題目鏈接:https://codeforces.ml/contest/571/problem/B

題目大意:

給一段序列a_i,你可以對其重排,要求重排之後的:

ans = \sum_i^{n-k}{|a_i-a_{i+k}|}最大

題目思路:

首先裂項相消:

a[i+k]-a[i]

a[i+2*k] - a[i+k]

sum = a[i+x*k]-a[i]

性質1:也就是這個每個數相距爲k的子序列的權值實際即爲a[i+x*k]-a[i]

性質2:

可以發現有長度爲n%k個 n/k+1的子序列

有k-n%k個 n/k的子序列

因爲要求重排,所以直接排序後,題目就轉換爲:

選出n%k段連續區間長度爲n/k+1的區間 和 k-n%k個區間長度爲n/k的區間,使得每段區間的最大值減最小值的和最小

所以令dp[i][k] 選了i段n/k+1的區間,k段n/k的區間

所以轉移方程:

令aim = i*(x+1) + k*x ,x = n/k

dp[i][k] = min(dp[i][k],dp[i-1][k] + num[aim]-num[aim-x])

dp[i][k] = min(dp[i][k],dp[i][k-1] + num[aim]-num[aim-x+1])

 

這種dp的狀態轉移方程並不常見,正確性是因爲選了i段與k段可以把當前選擇了多少個數給確定出來

這和之前牛客多校有一個狀態轉移非常的相似,不得不說還是要留心這種轉移

Code:

/*** keep hungry and calm CoolGuang!***/
#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=1e9+7;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll dp[5005][5005];
ll num[maxn];
int main()
{
    read(n);read(m);
    ll x = n/m;
    ll len1 = n%m;///x+1
    ll len2 = m-n%m;///x
    for(int i=1;i<=n;i++) read(num[i]);
    sort(num+1,num+1+n);
    for(int i=0;i<=len1;i++){
        for(int k=0;k<=len2;k++){
            if(!i&&!k){
                dp[i][k] = 0;
                continue;
            }
            dp[i][k] = INF;
            int aim = i*(x+1)+k*x;
            if(i) dp[i][k] =min(dp[i][k],dp[i-1][k]+num[aim]-num[aim-x]);
            if(k) dp[i][k] =min(dp[i][k],dp[i][k-1]+num[aim]-num[aim-x+1]);
        }
    }
    printf("%lld\n",dp[len1][len2]);
    return 0;
}
/**
5 2 2
1 5
1 2
2 3
3 4
4 5
**/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章