HNOI2010 公交線路 bus

2022-05-01 15:15:11 字數 1683 閱讀 2063

標籤:狀態壓縮+矩陣快速冪。

題解:首先看範圍,p<=10,那麼我們可以想到狀態壓縮。我們把從乙個長度為10的區間進行壓縮,1代表可以,那麼當值乙個區間的1的個數為k個,我們就認為他是合法的。要注意這裡所定義的區間,是有起點的,但是沒有記下來,因為沒有必要。然後我們就可以想一下狀態是怎麼轉移的。那麼可行的狀態有多少種呢?c(9,4)種。

然後兩種狀態是否能夠轉移是需要我們判斷的,我們每次轉移時只能移動乙個公共汽車,並且是移動最前面的汽車,這樣就可以避免重複統計的情況了前面說道區間是有起點的,那麼這一區間的最前的汽車向後移動,對於後面的下乙個狀態來說,他的起點是向後移動了一格的,所以只需把後乙個狀態向前左移一位,再去判斷是否有且僅有乙個不同即可。

(這裡有乙個小技巧,那就是我們眾所周知的樹狀陣列的lowbit,(x & -x)代表的是x從右往左數的第乙個1的位置,如100100就是位置3,那麼返回2^2。所以利用這一點可以很好的判斷乙個數有多少個1,以及兩個數是否僅僅相差一位不同。)

然後我們想想怎麼辦。我們每轉移乙個狀態,就是移動乙個汽車,那麼初始時到結束時的狀態就應該要移動n-k次。第一次汽車在起始站不要移動,後面要覆蓋所有的車站就是n-k次,那麼我們如過把狀態看成乙個點,能否轉移看成一條邊的話,乙個很美妙的結論我們就可以使用了。

對於乙個無權dag,他的鄰接矩陣的p次方就是兩點直接距離為p的方案數。我們就這樣使用矩陣快速冪,就可以統計出答案了。

終點狀態:第n-k個車站為壓縮狀態的第一位,後面k位都是1。所以是1111110000(k個1,p-k個0)。起始狀態是1000000000(其實按道理是1111110000,和終點狀態一樣,只是前面的i不同,省略了。)最後再使用初始矩陣去乘以轉移矩陣的n-k次方就行了。

其實來說,對於初始矩陣×轉移矩陣,這裡是很鬼畜的,初始矩陣s[1][end]。最後查詢s[1][end]。稍微算一算就可以發現,起始就是轉移矩陣中的s[end][end]吧!所以也可以直接輸出轉移矩陣,這也是合情合理的。

1 #include2 #include3 #include4

using

namespace

std;

5const

int maxn=150,mod=30031;6

intn,p,k,top,end;

7int

que[maxn];

8structed9

21return

b;22}23

}t,a;

24 ed pow(ed x,int

p)25

34return

x;35}36

bool can(int x,int

y)37

43int cal(int

x)44

51return

tot;52}

53int

main()

5462

for(int i=1;i<=top;i++)

63for(int j=1;j<=top;j++)

64if

(can(que[i],que[j]))

65 t.s[i][j]=1

;66 t=pow(t,n-k);

67 a.s[1][end]=1

;68 a=a*t;

69 cout<1][end]<70return0;

71 }

HNOI2010 公交線路

看到k,p的範圍這麼小,顯然要狀壓dp啊!但是要怎麼狀壓dp呢。我們先注意到每p個公交站,這k輛公交車都要至少出現一次。因為答案是按集合算的,所以公交車之間不做區別,換句話說就是我們可以講題目簡化一下 1 n的n個元素,k個集合,保證乙個元素只出現在乙個集合中 不能多餘乙個也不能少於乙個 任意乙個集...

HNOI2010 公交線路

狀壓 矩乘的好題。因為每 p 個位置中,每輛車就至少有 1 個位置,所以我們可以狀壓一下。設 f i j 表示 區間 i,i p 1 內的車站現在的規劃情況是 j 的方案數。顯然,必有 j 的第 p 位是 1 且 j 共有 k 位是 1 j 的第 p 位對應著 i 則 f i j sum f i 1...

hnoi2010 彈飛綿羊

題目描述很明確,現在的目標是均攤兩個操作的複雜度 現在我們已知有兩種方法 1.每次用o 1 的時間修改k值,用o n 的時間直接模擬回答詢問 2.每次修改了k值後用o n 的時間更新所有答案,o 1 時間回答 均攤這兩種操作,可以這樣做 由於只可以從前往後跳,所以可以把跳躍路徑壓縮,更新時把壓縮的部...