而如果这两个位置当前一个为
1
1
1 一个为
0
0
0 ,那么这两个位置异或
1
1
1 ,等价于
1
1
1 向
0
0
0 的方向平移了
w
w
w 个单位(
w
w
w 为两个位置间的距离)
注意上面的位置中也包括
n
+
1
n+1
n+1
预处理出
g
[
i
]
[
j
]
g[i][j]
g[i][j] 和
h
[
i
]
h[i]
h[i]
g
[
i
]
[
j
]
g[i][j]
g[i][j] 表示一个
1
1
1 在
i
i
i ,另一个
1
1
1 在
j
j
j ,在不影响其他位置的情况下把这两个
1
1
1 变成
0
0
0 的最少次数
h
[
i
]
h[i]
h[i] 表示一个
1
1
1 在
i
i
i ,在不影响其他位置的情况下把这个
i
i
i 变成
0
0
0 (位置
n
+
1
n+1
n+1 会被取反)
注意我们这里会用到的
i
,
j
i,j
i,j 仅仅是差分序列上最多
2
k
2k
2k 个为
1
1
1 的位置
考虑建图:
1
1
1 到
n
+
1
n+1
n+1 这
n
+
1
n+1
n+1 个点,对于任意
w
∈
a
w\in a
w∈a ,如果
∣
i
−
j
∣
=
w
|i-j|=w
∣i−j∣=w 则连边
(
i
,
j
)
(i,j)
(i,j) ,边权为
1
1
1
求
g
[
i
]
[
j
]
g[i][j]
g[i][j] 可以固定一个点
i
i
i ,以
i
i
i 为源点求单源最短路,就能求出所有的
g
[
i
]
[
]
g[i][]
g[i][]
注意边权为
1
1
1 ,可以 BFS 代替最短路
h
[
i
]
h[i]
h[i] 则是以
n
+
1
n+1
n+1 为源点 BFS
有了最短路之后,我们可以开始 DP 辣
f
[
S
]
f[S]
f[S] 表示将差分序列的下标集合
S
S
S 进行取反,其他位置不受影响的最小步数(
S
S
S 中仅包含不超过
2
k
2k
2k 个位置)
显然
f
[
∅
]
=
0
f[\emptyset]=0
f[∅]=0
(1)枚举
i
,
j
∈
S
,
i
≠
j
i,j\in S,i\ne j
i,j∈S,i̸=j ,表示
i
i
i 和
j
j
j 位置一起被取反,其他位置不受影响
f
[
S
]
=
min
(
f
[
S
]
,
f
[
S
−
i
−
j
]
+
g
[
i
]
[
j
]
)
f[S]=\min(f[S],f[S-i-j]+g[i][j])
f[S]=min(f[S],f[S−i−j]+g[i][j])
(2)枚举
i
∈
S
i\in S
i∈S ,表示
i
i
i 借助位置
n
+
1
n+1
n+1 实现取反,其他位置不受影响
f
[
S
]
=
min
(
f
[
S
]
,
f
[
S
−
i
]
+
h
[
i
]
)
f[S]=\min(f[S],f[S-i]+h[i])
f[S]=min(f[S],f[S−i]+h[i])
转移时可以假定
i
i
i 是
S
S
S 内的第一个元素(因为
S
S
S 内所有的位置都必须被取反)
最后答案显然为
f
[
a
l
l
]
f[all]
f[all] ,
a
l
l
all
all 为最终状态差分
01
01
01 序列上
1
1
1 的位置集合
复杂度
O
(
k
n
l
+
2
2
k
×
k
)
O(knl+2^{2k}\times k)
O(knl+22k×k)
Code
#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>inlineintread(){int res =0;bool bo =0;char c;while(((c =getchar())<'0'|| c >'9')&& c !='-');if(c =='-') bo =1;else res = c -48;while((c =getchar())>='0'&& c <='9')
res =(res <<3)+(res <<1)+(c -48);return bo ?~res +1: res;}template<classT>inline T Min(const T &a,const T &b){return a < b ? a : b;}constint N =1e4+5, E =25, M =205, C =(1<<20)+5, INF =0x3f3f3f3f;int n, k, m, arr[N], a[M], tot, w[E], g[E][E], dis[N], len, que[N],
f[C], Cm, dn[C];voidbfs(int S){memset(dis, INF,sizeof(dis));
dis[que[len =1]= S]=0;for(int i =1; i <= len; i++){int u = que[i];for(int j =1; j <= m; j++){int v = u + a[j];if(v <1|| v > n +1|| dis[v]< INF)continue;
dis[que[++len]= v]= dis[u]+1;}}}intmain(){
n =read(); k =read(); m =read();for(int i =1; i <= k; i++) arr[read()]=1;for(int i = n; i; i--) arr[i]^= arr[i -1];for(int i =1; i <= m; i++)
a[i]=read(), a[i + m]=-a[i];
m <<=1;for(int i =1; i <= n; i++)if(arr[i]) w[++tot]= i;for(int i =1; i <= tot; i++){bfs(w[i]);for(int j =1; j <= tot; j++)
g[i][j]= dis[w[j]];}bfs(n +1);memset(f, INF,sizeof(f));
f[0]=0;
Cm =1<< tot;for(int i =1; i <= tot; i++) dn[1<< i -1]= i;for(int S =1; S < Cm; S++){int id = dn[S &-S], T = S ^(S &-S);
f[S]=Min(f[S], f[T]+ dis[w[id]]);for(int i =1; i <= tot; i++)if((T >> i -1)&1)
f[S]=Min(f[S], f[T ^(1<< i -1)]+ g[id][i]);}printf("%d\n", f[Cm -1]== INF ?-1: f[Cm -1]);return0;}