2020牛客暑期多校训练营Two Matchings(动态规划,构造)

Two Matchings

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例1

输入

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

输出

16
16

说明

在这里插入图片描述

题目大意

在这里插入图片描述

分析

总成本最小,即为第一种匹配最小,第二种次小。
首先,最小很好求,只要排序后两两匹配即可。
但是次小比较麻烦,一开始想两种情况取了min,后来发现并没有那么简单。(但是时间到了)。
接下来看次小的4个元素的情况。
在这里插入图片描述
由此可以发现4个元素的次小即为a[4]-a[2]+a[3]-a[1]=a[4]+a[3]-a[2]-a[1] (已经排序)
再看次小的6个元素的情况。
在这里插入图片描述
由此可以发现6个元素的次小即为a[6]-a[1]+a[3]-a[2]+a[5]-a[4] (已经排序)

突然发现像dp啊,无论是什么数列都可以拆成4个元素为长度和6个元素为长度的数列
定义dp[i] 表示前i个数的次大值为dp[i]。
所以有
dp[i]=min(dp[i-4]+a[i]+a[i-1]-a[i-2]-a[i-3],dp[i-6]+a[i]+a[i-1]-a[i-2]+a[i-3]-a[i-4]-a[i-5]);

接下来就非常nice了,
WA了。
为啥呢。
dp的边界。
一开始我只有这么几行:

dp[4]=a[4]+a[3]-a[2]-a[1];
dp[6]=a[6]+a[5]-a[4]+a[3]-a[2]-a[1];

但是搞到dp[8]的时候要用到dp[2]……(无情),所以WA了几发。
dp[2]是非法的,所以dp[2]=inf。

接下来又很nice了,
又WA。
为啥呢。
inf有问题。
平时inf用的是1<<30,但是这里是long long啊。
所以

#define inf 1ll<<60
dp[2]=inf;
dp[4]=a[4]+a[3]-a[2]-a[1];
dp[6]=a[6]+a[5]-a[4]+a[3]-a[2]-a[1];


接下来……
别怕可以AC了。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1ll<<60
using namespace std;
const int MAXN=200100;
ll a[MAXN],dp[MAXN];
int main()
{
    int t,n;
    ll ans;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        ans=0;
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        for(int i=2;i<=n;i+=2) ans+=a[i]-a[i-1];
        dp[2]=inf;
        dp[4]=a[4]+a[3]-a[2]-a[1];
        dp[6]=a[6]+a[5]-a[4]+a[3]-a[2]-a[1];
        for(int i=8;i<=n;i+=2)
            dp[i]=min(dp[i-4]+a[i]+a[i-1]-a[i-2]-a[i-3],
            dp[i-6]+a[i]+a[i-1]-a[i-2]+a[i-3]-a[i-4]-a[i-5]);
        printf("%lld\n",ans+dp[n]);
    }
}//边界真的搞死人

END

有错即评。

猜你喜欢

转载自blog.csdn.net/zhangchizc/article/details/107450812