1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第三場)E Two Matchings

2020牛客暑期多校訓練營(第三場)E Two Matchings

2020牛客暑期多校訓練營(第三場)E Two Matchings

題解:

這個題目我覺得也有點難,主要是難以想到就dp 4和6。

首先 \(p_i!=i \,\,and \,\,p_{pi}=i\) 可得如果 \(p_x=i\) ,那麼 \(p_i=x\)

所以再來看這個要求的式子:\((\sum_{i=1}^{n}abs(a_i-a_{pi}))/2\)

可以知道一定存在 \(a_i=a_{pi}\)\(a_{pi}-a_i\) ,把這個2消去,所以最後就變成了對於這n個數,找到 \(\frac{n}{2}\) 對數之差最小,要找到兩個這樣的,並且這兩個不能有任意一對相同。

最後就是觀察出來,要麼拆成6,要麼拆成4,最後dp一下。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
#define debug(x) printf("debug:%s=%lld\n",#x,x);
//#define debug(x) cout << #x << ": " << x << endl
using namespace std;
const int maxn = 2e6+10;
typedef long long ll;
ll pre1[maxn],pre2[maxn];
ll dp[maxn],a[maxn];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) dp[i]=inf64,scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        dp[0]=0;
        for(int i=1;i<=n;i+=2) dp[0]+=a[i+1]-a[i];
        for(int i=4;i<=n;i++) pre1[i]=a[i]+a[i-1]-a[i-2]-a[i-3];
        for(int i=6;i<=n;i++) pre2[i]=a[i]+a[i-1]+a[i-3]-a[i-2]-a[i-4]-a[i-5];
        for(int i=4;i<=n;i++){
            if(i>=4) dp[i]=min(dp[i],dp[i-4]+pre1[i]);
            if(i>=6) dp[i]=min(dp[i],dp[i-6]+pre2[i]);
        }
        printf("%lld\n",dp[n]);
    }
}