• 2020牛客暑期多校第三场E-Two Matchings(规律DP)


    题目大意:给你一个数列,从$a_1->a_n$,你需要找到两个匹配序列$p,q$其中$p_i eq q_i$,使得$(sum_{i=1}^{n}abs(a_i-a_{p_i}))/2+(sum_{i=1}^{n}abs(a_i-a_{q_i}))/2$最小,问这个最小值是多少。n保证为偶数,sum(n)<=2e5

    输入

    2
    4
    0 8 0 0
    6
    3 1 4 1 5 9

    输出

    16
    16

    如果只是找一个序列的话很好找,我们将a排序,则可得1 2 3 4 5 6这样的有序数列,直接相邻两个相减就是最小值了。我们可以保留这个最小值,接下来我们找次小值,那么就是将数列向前移动一格,第一个数到末尾,然后相邻两个相减,那么这个是次优的。

    但很明显,这样做是有限制的,而显然,对于长度为4的序列,这个规律也成立。对于长度为8的序列,他可以拆成两个长度为4的序列,在这之后的数就可以由多个长度为4的和6的拼接而成。那么也就是说我们可以用DP来维护这个次小值。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int mac=2e5+10;
    
    int a[mac];
    ll dp[mac];
    
    int main(int argc, char const *argv[])
    {
        int t;
        scanf ("%d",&t);
        while (t--){
            int n;
            scanf ("%d",&n);
            for (int i=1; i<=n; i++)
                scanf ("%d",&a[i]);
            sort(a+1,a+1+n);
            ll ans=0;
            for (int i=1; i<=n; i+=2)
                ans+=a[i+1]-a[i];
            if (n>=4) dp[4]=a[3]-a[2]+a[4]-a[1];
            if (n>=6) dp[6]=a[3]-a[2]+a[5]-a[4]+a[6]-a[1];
            if (n>=8) dp[8]=a[3]-a[2]+a[4]-a[1]+a[7]-a[6]+a[8]-a[5];
            for (int i=10; i<=n; i+=2){
                ll s4=a[i]-a[i-3]+a[i-1]-a[i-2];
                ll s6=a[i]-a[i-5]+a[i-1]-a[i-2]+a[i-3]-a[i-4];
                dp[i]=min(dp[i-4]+s4,dp[i-6]+s6);
            }
            printf("%lld
    ",ans+dp[n]);
        }
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    六类人最适合做程序员!不善于撩妹的人竟然当选...哈哈
    20170926-构建之法:现代软件工程-阅读笔记
    Android Studio新建类头部注释和添加函数注释模板及快捷键
    android AysncTask使用
    Android Studio配置git,实现项目在github上的版本同步
    avloadingindicatorview 使用解析
    retrofit 基础使用
    retrofit 使用解析
    关于HTTP
    单例模式
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13351790.html
Copyright © 2020-2023  润新知