隐藏
「fstqwq的2017/10/08模拟题」星空 - 宽搜+动态规划+状态压缩 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「fstqwq的2017/10/08模拟题」星空 - 宽搜+动态规划+状态压缩

题目大意





题目分析

区间取反,按照套路做异或差分。
原题转化为一个有若干$0/1$的序列,每一次可以将$0$与指定长度外的$1$交换位置,若指定长度外的数是$0$即可将两个$0$消除,询问最少几次能够消除所有的$0$。

因为$0$最多有$8\times 2=16$个,因此不难想到状压动规。
设$f[s]$表示将状态改变为$s$最少需要几步。
其中状态$s$的每一位表示是否已经变为$1$。

考虑从左向右将$0$覆盖:

这表示用$pos1$的$0$将$pos2$的$0$消去。
$dist[pos1][pos2]$表示将$pos1$的$0$移动到$pos2$处的最少步数。
$dist[][]$明显可以使用$Bfs$预处理出来。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

const int maxn=40005,maxk=20;
int n,k,m,a[maxn],b[maxn],num[maxn],dist[maxk][maxn],vst[maxn],f[1<<16],cnt=0;
pair<int,int>p[maxk];

void Bfs(const pair<int,int>& s) {
queue<int>Q;
memset(vst,0,sizeof(vst));
dist[s.first][s.second]=0;
vst[s.second]=1;
Q.push(s.second);
while(!Q.empty()) {
int Now=Q.front();
Q.pop();
for(int i=1; i<=m; i++) {
if(Now>=b[i]&&!vst[Now-b[i]]) {
vst[Now-b[i]]=1;
dist[s.first][Now-b[i]]=dist[s.first][Now]+1;
Q.push(Now-b[i]);
}
if(Now+b[i]<=n&&!vst[Now+b[i]]) {
vst[Now+b[i]]=1;
dist[s.first][Now+b[i]]=dist[s.first][Now]+1;
Q.push(Now+b[i]);
}
}
}
}

int HighBit(int status) {
for(int i=cnt; i>=1; i--)
if(status&(1<<(i-1)))return i;
return 0;
}

void Dp() {
for(int s=1; s<(1<<cnt); s++) {
f[s]=0x7fffffff/2;
int pos=HighBit(s);
for(int i=pos-1; i>=1; i--)
if(s&(1<<(i-1)))f[s]=min(f[s],f[s^(1<<(pos-1))^(1<<(i-1))]+dist[pos][p[i].second]);
}
}

int main() {
n=Get_Int();
k=Get_Int();
m=Get_Int();
for(int i=1; i<=k; i++)a[Get_Int()]=1;
for(int i=1; i<=m; i++)b[i]=Get_Int();
for(int i=0; i<=n; i++) {
a[i]^=a[i+1];
if(a[i]) {
cnt++;
p[cnt]=make_pair(cnt,i);
}
}
memset(dist,0x3f,sizeof(dist));
for(int i=1; i<=cnt; i++)Bfs(p[i]);
Dp();
printf("%d\n",f[(1<<cnt)-1]);
return 0;
}
姥爷们赏瓶冰阔落吧~