哇很好很好的 dp 題目
yyr 講了這道題之後我瞬間就忘記啦,所以只能自己想了
大概思路還是記得噠
很明顯這題就是不能讓你去暴力列舉的,階乘級別的複雜度啊
但是怎麼去 dp 呢,單純的根據題意去嘗試定義 dp 方程似乎並不是很容易定義,這個時候需要嘗試構造模型:
選了乙個元素就不能選另乙個元素或者另外某些元素的模型是什麼呢?
是不是有樹形 dp 類似的題目:【沒有上司的舞會】,選了上司就不能選擇員工啊
但是無法將這個題目抽象成樹形 dp,因為乙個合法的小於 n 的數 x 有兩個爸爸:x/2 和 x/3,所以無法抽象成樹規!
還有什麼模型呢?
1 3 9 ……
2 6 18 ……
4 12 36 ……
定義 dp 方程 dp [ i ] [ ] += dp [ i - 1 ] [ ]
乙個狀態是合法的當且僅當它兩兩相鄰的位 & 值為 0!上下 & 的值為 1!
但是這樣的話有些數是不會出現在上圖的矩陣中的,哪些數呢?
當然是同時與 2、3 互質的數啦!
我們只需要預處理出所有與 2、3 互質的所有數,然後將每乙個作為矩陣的左上角構造就好啦!
ac**:
# include const int n = 23 , m = 17 , mod = 1000000001 ;
long long dp [ n ] [ ( 1 << m ) + 5 ] , to [ ( 1 << m ) + 5 ] ;
int tab [ ( 1 << m ) + 5 ] , num [ n ] , cnt [ n ] , sta [ ( 1 << m ) + 5 ] , buck [ ( 1 << m ) + 5 ] , tp [ ( 1 << m ) + 5 ];
int n , row , col , tot ;
long long gyx = 1 ;
void init ( )
if ( ( s1 & ( s1 >> 1 ) ) || ( ( s1 & ( s1 << 1 ) ) ) )
sta [ ++ tot ] = s1 ;
to [ s1 ] = tot ;
buck [ s1 ] = dig ;
} for ( int i = 1 ; i <= 11 ; i ++ )
}void get_tab ( )
void construct ( int x )
}long long dp ( )
} long long ans = 0 ;
for ( int i = 1 ; i <= num [ cnt [ row ] ] ; i ++ )
ans = ( ans + dp [ row ] [ sta [ i ] ] ) % mod ;
return ans ;
}int main ( )
printf ( "%lld" , gyx ) ;
return 0 ;
}
P3226 HNOI2012 集合選數 狀壓DP
題面 我們發現每個數 n nn 是否被選,只與 n3,n2,2 n,3n frac,frac,2n,3n 3n 2n 2n 3n 有關,那麼我們考慮建一張表,表上每一行按照 3 times 3 3的方式遞增,每一列按照 2 times 2 2的方式遞增,那麼對於同一張表,任意上下左右相鄰的數都是不能...
洛谷P3225 HNOI2012 礦場搭建
題意 煤礦工地可以看成是由隧道連線挖煤點組成的無向圖。為安全起見,希望在工地發生事故時所有挖煤點的工人都能有一條出路逃到救援出口處。於是礦主決定在某些挖煤點設立救援出口,使得無論哪乙個挖煤點坍塌之後,其他挖煤點的工人都有一條道路通向救援出口。請寫乙個程式,用來計算至少需要設定幾個救援出口,以及不同最...
洛谷 P3225 HNOI2012 礦場搭建
邊數n 500的挖煤點,需要設定盡量少的逃生出口,使得某個煤礦倒塌後,其他挖煤點的工人仍然可以通過某條路徑到達逃生出口,並給出逃生出口最少設定數量與方案數 多組資料 倒塌一座後 這一點令人想到割點 割點的倒塌會增加連通塊數量,產生隔斷 所以本題中顯然割點是比較重要的一種分析。先用tarjan跑出割點...