隐藏
「bzoj3003」LED - 宽搜+动态规划+状态压缩 | Bill Yang's Blog

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

0%

「bzoj3003」LED - 宽搜+动态规划+状态压缩

题目大意

    LED屏是由一个庞大的点阵小灯泡组成的,一开始每个小灯泡都不发光。每一行一共有$N$个小灯泡,依次标号为$1\sim n$。现在给定$K$个点,要求这$K$个点发光,其余点必须保持熄灭状态。而这块LED屏的操作方式各种奇葩,一共有$L$种操作方法,第$i$种表示你能将任意长度恰为$A_i$的连续一段灯泡的状态取反(灭变亮,亮变灭)。
    已知LED屏一共有$m$行,为了节省时间,请你算出每一行达到目标状态所需的最少操作次数。


题目分析

NOIP前做的原题:星空


代码

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
#include<bits/stdc++.h>

using namespace std;

inline int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(!isdigit(x)) {if(x=='-')bj=-1;x=getchar();}
while(isdigit(x)) {num=num*10+x-'0';x=getchar();}
return num*bj;
}

const int maxn=10005,maxl=105,maxk=25;

int n,l,m,a[maxk],p[maxk],len[maxl],vst[maxn],dist[maxn],Dist[maxk][maxk],f[1<<20],Log[1<<20];

void Bfs() {
for(int i=1; i<=n+1; i++)if(vst[i])p[m++]=i;
for(int i=0; i<m; i++) {
memset(dist,0x3f,sizeof(dist));
queue<int> Q;
Q.push(p[i]);
dist[p[i]]=0;
while(!Q.empty()) {
int now=Q.front();
Q.pop();
for(int j=1; j<=l; j++) {
if(now+len[j]<=n+1&&dist[now+len[j]]==0x3f3f3f3f) {dist[now+len[j]]=dist[now]+1;Q.push(now+len[j]);}
if(now-len[j]>=1&&dist[now-len[j]]==0x3f3f3f3f) {dist[now-len[j]]=dist[now]+1;Q.push(now-len[j]);}
}
}
for(int j=0; j<m; j++)Dist[i][j]=dist[p[j]];
}
}

void Clear() {
m=0;
memset(vst,0,sizeof(vst));
memset(Dist,0x3f,sizeof(Dist));
memset(f,0x3f,sizeof(f));
}

int main() {
for(int i=0; i<20; i++)Log[1<<i]=i;
int t=Get_Int();
while(t--) {
Clear();
n=Get_Int();
int k=Get_Int();
l=Get_Int();
for(int i=1; i<=k; i++)a[i]=Get_Int();
sort(a+1,a+k+1);
k=unique(a+1,a+k+1)-a-1;
for(int i=1; i<=k; i++)vst[a[i]]^=1,vst[a[i]+1]^=1;
for(int i=1; i<=l; i++)len[i]=Get_Int();
Bfs();
f[0]=0;
for(int S=1; S<(1<<m); S++) {
int u=Log[S&(-S)];
for(int i=u+1; i<m; i++)if(S>>i&1)f[S]=min(f[S],f[S^(1<<i)^(1<<u)]+Dist[u][i]);
}
printf("%d\n",f[(1<<m)-1]==0x3f3f3f3f?-1:f[(1<<m)-1]);
}
return 0;
}
姥爷们赏瓶冰阔落吧~