狀壓dp--P3943 星空
阿新 • • 發佈:2020-11-20
一道比較綜合的題
一些想法:
-
區間狀態取反:想到異或和差分
-
\(k\leq8\),那麼最多會有16個1,\(2^{16}\),想到狀態壓縮
-
給出\(m\)個區間長度,由他們組合出的區間長度的最小操作次數\(dp\)搞一下
-
每次操作會把一對1取反,把\(2^{16}\)種狀態依次把所有操作執行一遍,與得到的狀態連邊
-
求初始狀態和末狀態的最短路
code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #define N maxn using namespace std; int read(){ int x = 1,a = 0;char ch = getchar(); while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();} while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();} return x*a; } const int maxn = 1e6+10,inf = 1e9+7; queue<int>q; int n,k,m; int a[maxn],sum[maxn],s[maxn],cnt,arr[maxn]; int b[maxn],vis[maxn],f[N]; struct node{ int to,nxt,w; }ed[maxn*20]; int head[maxn],tot; void add(int u,int to,int w){ ed[++tot].to = to; ed[tot].w = w; ed[tot].nxt = head[u]; head[u] = tot; } int dis[maxn],vis1[maxn]; void SPFA(int s){ queue<int> q1;q1.push(s); for (int i = 0;i < (1<<cnt);i++) dis[i] = inf; dis[s] = 0;vis1[s] = 1; while (!q1.empty()){ int x = q1.front();q1.pop(); vis[x] = 0; for (int i = head[x];i;i = ed[i].nxt){ int to = ed[i].to; if (dis[to] > dis[x] + ed[i].w){ dis[to] = dis[x] + ed[i].w; if (!vis1[to]){ vis1[to] = 1; q1.push(to); } } } } } int main(){ n = read(),k = read(),m = read(); for (int i = 0;i <= n+1;i++) a[i] = 1; for (int i = 1;i <= k;i++){ int x = read();a[x] = 0; } for (int i = 1;i <= n+1;i++) sum[i] = a[i]^a[i-1]; for (int i = 1;i <= m;i++) b[i] = read(); for (int i = 1;i <= n+1;i++){ if (sum[i] == 1){ arr[++cnt] = 1; s[cnt] = i; } } for (int i = 1;i <= n;i++) f[i] = inf; f[0] = 0;q.push(0);vis[0] = 1; while(!q.empty()) { int u = q.front();q.pop(); for(int i = 1;i <= m;i ++) { if(u+b[i] <= n && vis[u+b[i]] == 0) { vis[u+b[i]] = 1,f[u+b[i]] = f[u] + 1; q.push(u+b[i]); } if(u-b[i] > 0 && vis[u-b[i]] == 0) { vis[u-b[i]] = 1,f[u-b[i]] = f[u] + 1; q.push(u-b[i]); } } } for (int k = 0;k < (1<<cnt);k++){ for (int i = 1;i <= cnt;i++){ for (int j = i+1;j <= cnt;j++){ int res = k; int val = f[s[j]-s[i]]; res ^= (1<<i>>1),res ^= (1<<j>>1); add(k,res,val); } } } int pos = (1<<cnt)-1; SPFA(pos); printf("%d\n",dis[0]); return 0; }