E.Two Matchings
题目链接-E.Two Matchings
题目大意
定义序列
p
p
p,满足如下要求:
- 是长度为 n n n的排列
- 满足 p p i = i 且 p i ≠ i p_{p_i}=i且p_i≠i ppi=i且pi=i
定义一个字符串的费用为
(
p
=
∑
n
=
1
N
a
b
s
(
a
i
−
a
p
i
)
)
/
2
(p = \sum\limits_{n=1}^Nabs(a_i-a_{pi}))/2
(p=n=1∑Nabs(ai−api))/2,
a
a
a为给出的权值数组
现求两个满足上述描述的序列
p
,
q
p,q
p,q ,同时还要满足任意
p
i
≠
q
i
p_i≠q_i
pi=qi,请你求出这两个序列的费用和的最小值是多少
解题思路
规
律
+
D
P
规律+DP
规律+DP
- 排列要想满足 p p i = i 且 p i ≠ i p_{p_i}=i且p_i≠i ppi=i且pi=i,只需将 [ 1 , 2 … n ] [1,2…n] [1,2…n]两两对调即可,要想满足费用和最小,我们可以先对数列 a a a排序,其中一个排列一定是 [ 2 , 1 , 4 , 3 … n , n − 1 ] [2,1,4,3…n,n-1] [2,1,4,3…n,n−1]这样,即交换相邻两位
- 然后我们再找费用次小的排列,因为任意 p i ≠ q i p_i≠q_i pi=qi,我们可以建一个偶环,将该偶环旋转一位 [ 2 , 3 … n , 1 ] [2,3…n,1] [2,3…n,1],即将第一个数移到最后一位数后面,这样次优的排列就为 [ 3 , 2 , 5 , 4 … 1 , n ] [3,2,5,4…1,n] [3,2,5,4…1,n]
- 根据样例,当 n = 6 n=6 n=6时,最小费用就为最优解+次优解 [ ( a 2 − a 1 ) + ( a 4 − a 3 ) + ( a 6 − a 5 ) ] + [ ( a 3 − a 2 ) + ( a 5 − a 4 ) + ( a 1 − a 6 ) ] [(a_2-a_1)+(a_4-a_3)+(a_6-a_5)]+[(a_3-a_2)+(a_5-a_4)+(a_1-a_6)] [(a2−a1)+(a4−a3)+(a6−a5)]+[(a3−a2)+(a5−a4)+(a1−a6)],即 ( a 6 − a 1 ) × 2 (a_6- a_1)×2 (a6−a1)×2;当 n = 4 n=4 n=4时,最小费用为 [ ( a 2 − a 1 ) + ( a 4 − a 3 ) ] + [ ( a 3 − a 2 ) + ( a 1 − a 4 ) ] [(a_2-a_1)+(a_4-a_3)]+[(a_3-a_2)+(a_1-a_4)] [(a2−a1)+(a4−a3)]+[(a3−a2)+(a1−a4)],即 ( a 4 − a 1 ) × 2 (a_4- a_1)×2 (a4−a1)×2
- 因为
n
=
2
n=2
n=2时,无论如何都不能满足任意
p
i
≠
q
i
p_i≠q_i
pi=qi,所以可以定义此时所需的费用为
INF
- 然后我们可以发现 n = 8 n=8 n=8时,把它拆成两个 4 4 4费用会更小, n = 10 n=10 n=10时,把它拆成一个 4 4 4和一个 6 6 6费用会更小,所以在这之后的数就可以由多个长度为4的和6的排列拼接而成,我们 d p dp dp来维护最小值即可
- 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=2e5+10;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
int a[N],dp[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
dp[0]=0;
dp[2]=INF;
dp[4]=a[4]-a[1];
dp[6]=a[6]-a[1];
for(int i=6;i<=n;i+=2)
dp[i]=min(dp[i-4]+a[i]-a[i-3],dp[i-6]+a[i]-a[i-5]);
cout<<dp[n]*2<<endl;
}
return 0;
}