Description
社交活动中有 n n n个男孩和 n n n个女孩。
他们玩的其中一场比赛是通过 p o c k y pocky pocky传递橡皮筋( p o c k y pocky pocky是一种长条饼干)。
与正常的社交活动游戏不同,只有两支队伍,男队和女队。
游戏规则如下,
1.两队都有 n n n个编号从 1 1 1到 n n n的马甲。
2.对手队将给出长度为 m m m的整数序列 a 1 , . . . , a m a_1,...,a_m a1,...,am。所有数字将在 1 1 1到 n n n(含 n n n)之间,并且所有相邻数字都不相同(对于所有 1 ≤ i < m , a i ≠ a i + 1 1\le i<m,a_i\neq a_{i+1} 1≤i<m,ai̸=ai+1)。
3.在对手队给出序列之后,另一队开始计划背心的穿着策略。请注意,团队成员在游戏过程中不能交换背心。
4.当比赛开始时,橡皮筋将被放在穿着 a 1 a_1 a1编号的背心的队员嘴中的 p o c k y pocky pocky上。 然后,穿着 a 1 a_1 a1编号的背心的队员必须将橡皮筋传递给穿着 a 2 a_2 a2编号的背心的队员,而不能用手,如此进行下去…。当橡皮筋通过 m − 1 m - 1 m−1次并且已经在穿着 a m a_m am编号的背心的队员的 p o c k y pocky pocky上时,游戏将结束。
5.第一队完成是胜利的队。
S h i k y Shiky Shiky是算法大师。他从未在任何战略游戏中失利。他相信他会像以前一样赢得这场比赛。
他发现两名队员之间的身高差距越大,他们之间的橡皮筋越难通过。
基于这一观察,他定义了一次传递橡皮筋的难度为身高差的绝对值。
你是 S h i k y Shiky Shiky对手队伍的领导者。
你知道 S h i k y Shiky Shiky编写了一个程序来计算他的团队难度的最小可能总和。
既然你不想输,你决定为你的团队编写一个具有相同功能的程序。
PS :由于 S h i k y Shiky Shiky有女朋友,所以你不能引诱他获取源代码,而且他女朋友没参加这场比赛( 2333333 2333333 2333333
Input
第一行有两个整数 n n n和 m m m。 它表明有 n n n个男孩和 n n n个女孩,而 S h i k y Shiky Shiky的团队会给你一个长度为 m m m的序列。
第二行有 n n n个整数 h 1 , h 2 . . . , h n h_1,h_2 ...,h_n h1,h2...,hn,表示你所有团队成员的身高。
第三行有 m m m个整数 a 1 , a 2 . . . , a m a_1,a_2 ...,a_m a1,a2...,am,表示 S h i k y Shiky Shiky团队给出的序列。
( 1 ≤ n ≤ 20 , 2 ≤ m ≤ 1000 , 120 ≤ h i ≤ 240 , 1 ≤ a i ≤ n , a i ≠ a i + 1 ) (1\le n\le 20,2\le m\le 1000,120\le h_i\le 240,1\le a_i\le n,a_i\neq a_{i+1}) (1≤n≤20,2≤m≤1000,120≤hi≤240,1≤ai≤n,ai̸=ai+1)
Output
输出一个整数表示团队难度的最小可能总和。
Sample Input
3 3
170 175 180
1 2 3
Sample Output
10
Solution
状压
D
P
DP
DP,从低到高安排身高,以
d
p
[
S
]
dp[S]
dp[S]表示已经给
S
S
S状态的人安排好了前
n
u
m
[
S
]
num[S]
num[S]个身高,其中
n
u
m
[
S
]
num[S]
num[S]表示
S
S
S二进制表示中
1
1
1的个数,对于
S
S
S中为
1
1
1的位置
x
x
x,考虑给
x
x
x身高为
h
n
u
m
[
S
]
h_{num[S]}
hnum[S],那么把
x
x
x安排进去之后,对团队难度的贡献分为两部分:正部分为
x
x
x与
S
S
S中为
1
1
1位置
y
y
y的相邻次数,因为
y
y
y的身高必然小于
x
x
x,而负部分为
x
x
x与
S
S
S中为
0
0
0位置
y
y
y的相邻次数,因为
y
y
y的身高必然大于
x
x
x,记
n
u
m
[
x
]
[
y
]
num[x][y]
num[x][y]为
a
1
,
.
.
.
,
a
m
a_1,...,a_m
a1,...,am中
x
,
y
x,y
x,y相邻的次数,那么即可
O
(
n
)
O(n)
O(n)统计该贡献,记为
z
z
z,进而有转移
d
p
[
S
]
=
m
i
n
(
d
p
[
S
]
,
d
p
[
S
−
2
x
]
+
z
⋅
h
n
u
m
[
S
]
)
dp[S]=min(dp[S],dp[S-2^x]+z\cdot h_{num[S]})
dp[S]=min(dp[S],dp[S−2x]+z⋅hnum[S])
d
p
[
2
n
−
1
]
dp[2^n-1]
dp[2n−1]记为答案,时间复杂度
O
(
n
2
⋅
2
n
)
O(n^2\cdot 2^n)
O(n2⋅2n)
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f,maxn=(1<<20)+5;
int n,m,h[22],a[1005],cnt[22][22],dp[maxn],num[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&h[i]);
sort(h+1,h+n+1);
for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
a[i]--;
if(i>1)cnt[a[i]][a[i-1]]++,cnt[a[i-1]][a[i]]++;
}
int N=1<<n;
num[0]=0;
for(int i=1;i<N;i++)num[i]=num[i/2]+(i&1);
for(int i=1;i<N;i++)dp[i]=INF;
dp[0]=0;
for(int S=1;S<N;S++)
for(int x=0;x<n;x++)
if((S>>x)&1)
{
int y=0;
for(int i=0;i<n;i++)
if((S>>i)&1)y+=cnt[i][x];
else y-=cnt[i][x];
dp[S]=min(dp[S],dp[S^(1<<x)]+y*h[num[S]]);
}
printf("%d\n",dp[N-1]);
return 0;
}