#12【BZOJ3003】LED BFS+状压DP

时间:2023-03-10 06:30:58
#12【BZOJ3003】LED BFS+状压DP

题解:

看到区间修改先想一下差分

这题用差分是为了分析问题

现在的问题就变成了

原序列全为0,要使得特定的k个点变为1,每个操作改变x,y+1

然后我们会发现

对于二元组a,b我们要修改它,实际上是在找连续的区间相连,所以实质上是最短路

为什么要差分了才能这么做呢

因为原来的区间修改可能中间涉及了有效点而变得复杂

现在每次有效操作不会影响到中间的有效点

接下来状压dp这是显然的

对于每一个状态,枚举二元组(确定其中一个值,枚举另一个值)

这是因为被确定的这个值一定是其中一个二元组

在做这个之前,还需要证明的是三元组,4元组。。。是无效的

首先奇数是不可能的

看一下四元组,一定是可以拆分成两个无关的二元组

非常的智障的是我写最短路的时候只往一边走。。 应该要往两边扩展

#include <bits/stdc++.h>
using namespace std;
int T,n,m,k;
int len[],s[];
#define rg register
#define IL inline
#define N 10100
#define N2 1100000
#define INF 1e9
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
char ss[<<],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++;}
template<class T>void read(T&x){
rg int f=,c;while(c=gc(),c<||<c)if(c=='-')f=-;x=c^;
while(c=gc(),<c&&c<)x=(x<<)+(x<<)+(c^);x*=f;
}
bool ff[N],f[N];
queue<int> q;
int dis[][N],dp[N2];
int main()
{
freopen("noi.in","r",stdin);
freopen("noi.out","w",stdout);
std::ios::sync_with_stdio(false);
read(T);
for (rg int TT=;TT<=T;TT++)
{
memset(ff,,sizeof(ff));
int kk=;
read(n); read(m); read(k);
rg int x,y;
for (rg int i=;i<=m;i++)
read(x),ff[x]^=,ff[x+]^=;
for (rg int i=;i<=n+;i++)
if (ff[i]) s[++kk]=i;
for (rg int i=;i<=kk;i++)
for (rg int j=;j<=n+;j++)
dis[i][j]=INF;
for (rg int i=;i<=k;i++) read(len[i]);
for (rg int i=;i<N2;i++) dp[i]=INF;
for (rg int i=;i<=kk;i++)
{
memset(f,,sizeof(f));
q.push(s[i]); dis[i][s[i]]=;
while (!q.empty())
{
rg int x=q.front(); q.pop();
for (rg int j=;j<=k;j++)
if (x-len[j]>&&f[x-len[j]])
{
dis[i][x-len[j]]=dis[i][x]+;
f[x-len[j]]=;
q.push(x-len[j]);
}
for (rg int j=;j<=k;j++)
if (x+len[j]<=n+&&f[x+len[j]])
{
dis[i][x+len[j]]=dis[i][x]+;
f[x+len[j]]=;
q.push(x+len[j]);
}
}
}
/* for (int i=1;i<=kk;i++)
{
cout<<endl<<endl;
for (int j=1;j<=n;j++)
cout<<dis[i][j]<<" ";
} */
for (rg int i=;i<=kk;i++)
for (rg int j=;j<i;j++)
{
int x=(<<(i-))|(<<(j-));
dp[x]=dis[i][s[j]];
}
for (rg int i=;i<=(<<kk)-;i++)
{
rg int x;
for (rg int j=;j<kk;j++)
if ((i>>j)&)
{
x=j+; break;
}
for (rg int j=;j<kk;j++)
if ((i>>j)&&&j+!=x)
{
y=(<<j)|(<<(x-));
dp[i]=min(dp[i],dp[y]+dp[i^y]);
}
}
/* for (rg int i=1;i<=(1<<kk)-1;i++)
for (rg int j=i;j;j=i&(j-1))
{
for
dp[i]=min(dp[i],dp[j]+dp[i^j]);
} */
dp[(<<kk)-]==INF?cout<<-<<endl:cout<<dp[(<<kk)-]<<endl;
}
return ;
}