題面
你有 n n n個選手,每個選手都有一個勢力值,你要把他們分成多個小組,每個小組最少要有3個人,每個小組的多樣性值為勢力值最大值減去最小值,問讓你提出一種分組方式使得多樣性總和最小。
解題方法
我們發現組分的越多,答案一定越小,所以說我們發現每個小組的人數一定是
3
−
5
3-5
3−5人,然后我們就可以通過
d
p
dp
dp求答案了,我們能夠發現的遞推式如下:
d
p
[
i
+
3
]
=
m
i
n
(
d
p
[
i
+
3
]
,
d
p
[
i
]
+
a
[
i
+
2
]
−
a
[
i
]
)
;
d
p
[
i
+
4
]
=
m
i
n
(
d
p
[
i
+
4
]
,
d
p
[
i
]
+
a
[
i
+
3
]
−
a
[
i
]
)
;
d
p
[
i
+
5
]
=
m
i
n
(
d
p
[
i
+
5
]
,
d
p
[
i
]
+
a
[
i
+
4
]
−
a
[
i
]
)
;
dp[i+3]=min(dp[i+3],dp[i]+a[i+2]-a[i]);\\ dp[i+4]=min(dp[i+4],dp[i]+a[i+3]-a[i]);\\ dp[i+5]=min(dp[i+5],dp[i]+a[i+4]-a[i]);
dp[i+3]=min(dp[i+3],dp[i]+a[i+2]−a[i]);dp[i+4]=min(dp[i+4],dp[i]+a[i+3]−a[i]);dp[i+5]=min(dp[i+5],dp[i]+a[i+4]−a[i]);
然後就可以求出答案了。
代碼
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int v,pos;
}a[200100];
bool comp(node x,node y)
{
return x.v<y.v;
}
int dp[200100];
int minn[200100];
int z[200100];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].v),a[i].pos=i;
sort(a+1,a+n+1,comp);
for(int i=2;i<=n+1;i++)
{
minn[i]=-1;
dp[i]=9e8+7;
}
for(int i=1;i<=n;i++)
{
if(i+3<=n+1)
if(dp[i+3]>dp[i]+a[i+2].v-a[i].v) dp[i+3]=dp[i]+a[i+2].v-a[i].v,minn[i+3]=i ;
if(i+4<=n+1)
if(dp[i+4]>dp[i]+a[i+3].v-a[i].v) dp[i+4]=dp[i]+a[i+3].v-a[i].v,minn[i+4]=i;
if(i+5<=n+1)
if(dp[i+5]>dp[i]+a[i+4].v-a[i].v) dp[i+5]=dp[i]+a[i+4].v-a[i].v,minn[i+5]=i;
}
int tot=0;
int now=n+1;
while(now!=1)
{
for(int i=now-1;i>=minn[now];i--)
z[a[i].pos]=tot;
tot++;
now=minn[now];
}
cout<<dp[n+1]<<' '<<tot<<'\n';
for(int i=1;i<=n;i++)
cout<<z[i]+1<<' ';
return 0;
}