题目描述
输入描述:
输出描述:
示例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
有错即评。