[省选联考 2020 A/B 卷] 信号传递(状压dp + 卡空间)
problem
luogu-P6622
一條道路上從左至右排列著 mmm 個信號站,初始時從左至右依次編號為 1,2,…,m1,2,\dots,m1,2,…,m,相鄰信號站之間相隔 111 單位長度。
每個信號站只能往它右側的任意信號站傳輸信號(稱為普通傳遞),每單位長度距離需要消耗 111 單位時間。
道路的最左側有一個控制塔,它在最左側信號站的左側,與其相隔 111 單位長度。
控制塔能與任意信號站進行雙向信號傳遞(稱為特殊傳遞),但每單位長度距離需要消耗 kkk 個單位時間。
對于給定的長度為 nnn 的信號傳遞序列 SSS,傳遞規則如下:
阿基作為大工程師,他能夠任意多次交換任意兩個信號站的位置,即他能夠重排信號站的順序,這樣會使得 SSS 消耗的傳遞時間改變。
現在阿基想知道,在他重排信號站順序后,SSS 所消耗的傳遞時間最小能是多少。
solution
假設坐標在 x,yx,yx,y 的兩個信號塔之間有一次 x→yx\rightarrow yx→y 的傳遞,可以形式化地表示:
{y?xx≤ykx+kyx>y\begin{cases} y-x&&x\le y\\ kx+ky&&x>y \end{cases} {y?xkx+ky??x≤yx>y?
這是同構的,也就是說對于每個傳遞的貢獻可以拆成兩個信號塔的各自貢獻。
假設坐標在 yyy 的信號塔,如果有坐標 x→yx\rightarrow yx→y 的傳遞。
- 則對于 yyy 所代表的信號塔而言:
- x≤yx\le yx≤y,產生 111。
- x>yx>yx>y,產生 kkk。
- 反之同理,對于 xxx 所代表的信號塔而言:
- x≤yx\le yx≤y,產生 ?1-1?1。
- x>yx>yx>y,產生 kkk。
則最終代價等于每個點的貢獻乘以其坐標再求和。
具體的數學形式推導:
設 cnt(i,j):cnt(i,j):cnt(i,j): 有多少次信號塔 i→ji\rightarrow ji→j 的傳遞,即 cnt(i,j)=∑k=1n[Sk=i][Sk+1=j]cnt(i,j)=\sum_{k=1}^n[S_k=i][S_{k+1}=j]cnt(i,j)=∑k=1n?[Sk?=i][Sk+1?=j]。
設下標 ppp 處是 idpid_pidp? 號信號站,推導一下每個下標對答案的貢獻。
ans=∑i=1m∑j=i+1mcnt(idi,idj)?(j?i)+∑i=1m∑j=1i?1cnt(idi,idj)?(i+j)?kans=\sum_{i=1}^m\sum_{j=i+1}^mcnt(id_i,id_j)*(j-i)+\sum_{i=1}^m\sum_{j=1}^{i-1}cnt(id_i,id_j)*(i+j)*k ans=i=1∑m?j=i+1∑m?cnt(idi?,idj?)?(j?i)+i=1∑m?j=1∑i?1?cnt(idi?,idj?)?(i+j)?k=∑i=1mi(∑j=i+1m(k?cnt(idj,idi)?cnt(idi,idj))+∑j=1i?1(k?cnt(idi,idj)+cnt(idj,idi)))=\sum_{i=1}^mi\bigg(\sum_{j=i+1}^m\Big(k*cnt(id_j,id_i)-cnt(id_i,id_j)\Big)+\sum_{j=1}^{i-1}\Big(k*cnt(id_i,id_j)+cnt(id_j,id_i)\Big)\bigg) =i=1∑m?i(j=i+1∑m?(k?cnt(idj?,idi?)?cnt(idi?,idj?))+j=1∑i?1?(k?cnt(idi?,idj?)+cnt(idj?,idi?)))
設 f(s):f(s):f(s): 考慮到 ∣s∣|s|∣s∣ 位(∣s∣:s|s|:s∣s∣:s 二進制下 111 的個數),前 ∣s∣|s|∣s∣ 位的信號站編號集合為 sss 時的最小代價。
那么 ∑j=i+1m(k?cnt(idj,idi)?cnt(idi,idj))+∑j=1i?1(k?cnt(idi,idj)+cnt(idj,idi))\sum_{j=i+1}^m\Big(k*cnt(id_j,id_i)-cnt(id_i,id_j)\Big)+\sum_{j=1}^{i-1}\Big(k*cnt(id_i,id_j)+cnt(id_j,id_i)\Big)∑j=i+1m?(k?cnt(idj?,idi?)?cnt(idi?,idj?))+∑j=1i?1?(k?cnt(idi?,idj?)+cnt(idj?,idi?)) 形式中的 jjj 其實就是以 ∣s∣|s|∣s∣ 為劃分點,分成在 sss 集合內的編號信號塔和不在的信號塔。
于是我們可以預處理這部分的貢獻,只需要知道 iii 和集合 sss 即可。
規范化的,令 g(i,s)=∑j∈?s∧j≠ik?cnt(idj,idi)?cnt(idi,idj)+∑j∈sk?cnt(idi,idj)+cnt(idj,idi)g(i,s)=\sum_{j\not\in s\wedge j\ne i}k*cnt(id_j,id_i)-cnt(id_i,id_j)+\sum_{j\in s}k*cnt(id_i,id_j)+cnt(id_j,id_i)g(i,s)=∑j?∈s∧j?=i?k?cnt(idj?,idi?)?cnt(idi?,idj?)+∑j∈s?k?cnt(idi?,idj?)+cnt(idj?,idi?)。
先預處理 g(i,0)g(i,0)g(i,0),然后每次枚舉 sss 二進制下的一個 111(隨便拎個 lowbitlowbitlowbit 位)即可 O(1)O(1)O(1) 轉移。
一個數從 ∈?s\not\in s?∈s 到變成 ∈s\in s∈s,先減去原來的代價再加上 ∈s\in s∈s 里面時計算的代價。
時間復雜度 O(2mm)O(2^mm)O(2mm)。
那么 fff 數組的轉移就比較簡潔了:枚舉 sss 二進制下的 111 位置,取較小值。
f(s)=min?i∈s{f(s?{i})+∣s∣g(i,s?{i})}f(s)=\min_{i\in s}\Big\{f(s-\{i\})+|s|g(i,s-\{i\})\Big\} f(s)=i∈smin?{f(s?{i})+∣s∣g(i,s?{i})}
到此時空復雜度均為 O(m2m)O(m2^m)O(m2m)。
發現空間起飛了。其實觀察數據分布就會發現,mmm 的變化只有 111,對空間的限制明顯狠于時間。
也就是說,難得的需要來考慮卡一下空間了。
有各種大力優化空間的妙做法,但是從應試角度,以及出題角度,私以為這種做法以及可以應付了:
轉移方程中 g(i,s)g(i,s)g(i,s) ,若 i∈si\in si∈s 則是不合法的,顯然不會被用到。
換言之,對于每個 iii,最多只有 2222^{22}222 種狀態。
如果只存合法狀態,內存就會 /2/2/2,在時間上而言是常數的東西這里就是個大優化了。
考慮怎么減半?
- 只用讓每個 sss 的前 i?1i-1i?1 位不動,(s&(1<<i)-1);
- 其余位置整體右移一位,相當于 /2/2/2,(s^(s&(1<<i)-1))>>1;
- 最后把兩者加起來即可。
code
#include <bits/stdc++.h> using namespace std; #define maxn 23 int n, m, k; int f[1 << maxn], g[maxn][1 << maxn - 1], cnt[maxn][maxn]; int lowbit( int x ) { return x & -x; } int main() {scanf( "%d %d %d", &n, &m, &k );for( int i = 1, x, lst = -1;i <= n;i ++ ) {scanf( "%d", &x ); x --;if( ~ lst ) ++ cnt[lst][x];lst = x;}for( int i = 0;i < m;i ++ ) {for( int j = 0;j < m;j ++ )if( i ^ j ) g[i][0] += k * cnt[j][i] - cnt[i][j];for( int s = 1;s < (1 << m);s ++ )if( ! (s >> i & 1) ) {int t = s ^ lowbit( s );int j = __builtin_ffs( s ) - 1;g[i][(s & (1<<i)-1) + ((s ^ (s & (1<<i)-1)) >> 1)] = g[i][(t & (1<<i)-1) + ((t ^ (t & (1<<i)-1)) >> 1)] + (k * cnt[i][j] + cnt[j][i]) - (k * cnt[j][i] - cnt[i][j]);}}memset( f, 0x3f, sizeof( f ) ); f[0] = 0;for( int s = 1;s < (1 << m);s ++ ) {int x = __builtin_popcount( s );for( int i = 0;i < m;i ++ )if( s >> i & 1 ) {int t = s ^ (1 << i);f[s] = min( f[s], f[t] + x * g[i][(t & (1<<i)-1) + ((t ^ (t & (1<<i)-1)) >> 1)] );}}printf( "%d\n", f[(1 << m) - 1] );return 0; }總結
以上是生活随笔為你收集整理的[省选联考 2020 A/B 卷] 信号传递(状压dp + 卡空间)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [JSOI2016] 最佳团体(0/1分
- 下一篇: 【学习笔记】WQS二分详解及常见理解误区