#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[200],s[200]; #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[1<<17],*A=ss,*B=ss; inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?EOF:*A++;} template<class T>void read(T&x){ rg int f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48; while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f; } bool ff[N],f[N]; queue<int> q; int dis[200][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=1;TT<=T;TT++) { memset(ff,0,sizeof(ff)); int kk=0; read(n); read(m); read(k); rg int x,y; for (rg int i=1;i<=m;i++) read(x),ff[x]^=1,ff[x+1]^=1; for (rg int i=1;i<=n+1;i++) if (ff[i]) s[++kk]=i; for (rg int i=1;i<=kk;i++) for (rg int j=1;j<=n+10;j++) dis[i][j]=INF; for (rg int i=1;i<=k;i++) read(len[i]); for (rg int i=0;i<N2;i++) dp[i]=INF; for (rg int i=1;i<=kk;i++) { memset(f,1,sizeof(f)); q.push(s[i]); dis[i][s[i]]=0; while (!q.empty()) { rg int x=q.front(); q.pop(); for (rg int j=1;j<=k;j++) if (x-len[j]>0&&f[x-len[j]]) { dis[i][x-len[j]]=dis[i][x]+1; f[x-len[j]]=0; q.push(x-len[j]); } for (rg int j=1;j<=k;j++) if (x+len[j]<=n+1&&f[x+len[j]]) { dis[i][x+len[j]]=dis[i][x]+1; f[x+len[j]]=0; 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=1;i<=kk;i++) for (rg int j=1;j<i;j++) { int x=(1<<(i-1))|(1<<(j-1)); dp[x]=dis[i][s[j]]; } for (rg int i=1;i<=(1<<kk)-1;i++) { rg int x; for (rg int j=0;j<kk;j++) if ((i>>j)&1) { x=j+1; break; } for (rg int j=0;j<kk;j++) if ((i>>j)&1&&j+1!=x) { y=(1<<j)|(1<<(x-1)); 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[(1<<kk)-1]==INF?cout<<-1<<endl:cout<<dp[(1<<kk)-1]<<endl; } return 0; }