洛谷p3943 星空 題解(奇妙轉化 狀壓)

2021-08-28 15:28:39 字數 3006 閱讀 5842

傳送門

感覺真的是一道挺有質量的好題,練到了。

我就不囉嗦部分分了,直接說正解吧。

第一印象:資料範圍k≤8

k\leq8

k≤8,標籤上說也許是個狀壓dp

正式思考:首先發現乙個事情:把一段區間取反非常麻煩。我們可以考慮類似差分的思想,處理出d[i

]=a[

i]xo

ra[i

+1

]d[i]=a[i]\ xor\ a[i + 1]

d[i]=a

[i]x

ora[

i+1]

,於是將區間取反就變成了d

dd上的兩個端點取反。

那麼問題就轉化為:給定乙個01

0101

串和乙個距離集合l

ll,每次可以選兩個位置i

ii和j

jj將它們取反,但是必須滿足∣j−

i∣∈l

|j-i|\in l

∣j−i∣∈

l,問最少要操作多少次才能把它們全部變成1。

考慮將兩個位置上的數取反:

所以問題又轉化為:乙個n

nn個頂點的無向圖,有不超過2k2k

2k個點上有妹子;每次可以讓乙個點上的妹子走到另乙個點,但是走的距離有限制;兩個妹子碰到一起就都是你的了;問至少要操作多少次才能泡遍所有妹子。皮這一下十分開心

要讓兩個妹子走到一起並且操作次數盡量少,顯然要走最短路。所以就先spfa(或者可以看做乙個簡單bfs)求出每個有妹子的點到其它所有點的最短距離。複雜度o(n

mk

)o(nmk)

o(nmk)

。於是問題最終轉化為:有不超過2k2k

2k個物品,選擇其中兩個可以花一定代價消去,問最小代價和。

簡單狀壓dp即可。

有乙個小細節需要注意:對於當前狀態s

ss,可以列舉兩個不在s

ss中的物品i,j

i,ji,

j進行拓展,如果直接這樣列舉複雜度是o(k

222k

)o(k^22^)

o(k222

k)的,在某些題中可能被卡(本題應該可以過)。乙個常見優化是,物品i

ii就直接選擇不在s

ss中的編號最小的物品,而不是列舉i

ii,這樣的話複雜度就是o(k

∗22k

)o(k*2^)

o(k∗22

k)。

#include

#include

#include

#include

#include

template

<

typename t>

inline

void

read

(t& t)

inline

intread()

#if __cplusplus >= 201103l

template

<

typename t,

typename..

. args>

inline

void

read

(t& t, args&..

. args)

#else

template

<

typename t1,

typename t2>

inline

void

read

(t1& t1, t2& t2)

template

<

typename t1,

typename t2,

typename t3>

inline

void

read

(t1& t1, t2& t2, t3& t3)

template

<

typename t1,

typename t2,

typename t3,

typename t4>

inline

void

read

(t1& t1, t2& t2, t3& t3, t4& t4)

template

<

typename t1,

typename t2,

typename t3,

typename t4,

typename t5>

inline

void

read

(t1& t1, t2& t2, t3& t3, t4& t4, t5& t5)

#endif

// c++11

#ifdef win32

#define llio "%i64d"

#else

#define llio "%lld"

#endif

// win32 long long

#define rep(i, a, b) for (int i = (a); i <= (b); ++i)

#define rrep(i, a, b) for (int i = (a); i >= (b); --i)

#define erep(i, x) for (int i = head[x]; i; i = next[i])

const

int maxn =

4e4+

207;

const

int inf = int_max >>3;

int a[maxn]

, b[maxn]

;int dist[20]

[maxn]

, pos[maxn]

;int dp[

1<<18]

;int n, m, k, zero;

inline

void

spfa

(int ss)}}

void

dfs(

int s)}}

intmain()

洛谷P3943 星空 題解

一道很好的鍛鍊思維難度的題,如果您能在考場上直接想出來的話,提高組450分以上就沒問題了吧。別像作者一樣看了好幾篇題解才勉強會 先提取出題目大意 給定乙個長度n 40000的01串,其中1的個數 8,有m種操作,每次操作都是把乙個該操作對應長度的區間取反,或者說異或上1,求使整個串變為只有0的串的最...

洛谷P3943 星空

洛谷p3943 星空 命運偷走如果只留下結果,時間偷走初衷只留下了苦衷。你來過,然後你走後,只留下星空。逃不掉的那一天還是來了,小 f 看著夜空發呆。天上空蕩蕩的,沒有一顆星星 大概是因為天上吹不散的烏雲吧。心裡吹不散的烏雲,就讓它在那裡吧,反正也沒有機會去改變什麼了。小 c 拿來了一長串星型小燈泡...

洛谷 P3943 星空

有乙個長度為n的01序列,有k個1 每次可以將給定長度的子串取反,即0 1,1 0 求最少幾次可以將整個序列都變為0 差分 狀壓dp 首先將原序列異或差分 每消去一對1就是將1移到一起 先用bfs預處理出每兩個1移到一起的最小步數 然後用狀壓dp來求總的最小步數 include include co...