BZOJ2734 集合選數

2021-08-02 01:26:25 字數 1886 閱讀 6776

《集合論與圖論》這門課程有一道作業題,要求同學們求出的所有滿足以 下條件的子集:若 x 在該子集中,則 2x 和 3x 不能在該子集中。同學們不喜歡這種具有列舉性 質的題目,於是把它變成了以下問題:對於任意乙個正整數 n≤100000,如何求出 的滿足上述約束條件的子集的個數(只需輸出對 1,000,000,001 取模的結果),現在這個問題就 交給你了。

只有一行,其中有乙個正整數 n,30%的資料滿足 n≤20。

僅包含乙個正整數,表示有多少個滿足上述約束條件 的子集。

4

8

有8 個集合滿足要求,分別是空集,,,,,,,。

狀態壓縮dp

這道題目的思路真的很巧。我們可以構造乙個矩陣如下x3x

9x27 x

2x6x

18x54x

4x12x

36 x

108 x

8x24x

72x216 x

此時令x=

1 ,我們可以得到13

92726

1854412

36108824

72216

我們可以觀察到,每個數和他相鄰的數都不可同時取,可以計算出本矩陣中取數的方案數。

但是我們會發現漏了5和7,那麼按照上面進行構造。

計算出所有矩陣的結果,因為不同矩陣間的數是一定可以共同存在的,此時乘法原理,將各矩陣求得的方案數相乘取模即為答案。

如何統計方案數 f[

i][j

] 表示當前處理到第

i 行,本行的狀態為

j。那麼看一下j&(j>>1),j&k(k為上一行的某狀態)是否都為0,如果是那麼就從f[

i−1]

[k] 轉移而來。 f[

i][j

]=∑(

f[i−

1][k

]|ki

sok)

#include 

#include

#include

#define max(a,b) ((a)>(b)?(a):(b))

#define min(a,b) ((a)<(b)?(a):(b))

typedef

long

long ll;

const

int mod = 1000000001;

const

int size = 20+1;

ll ans=1;

int n;

int a[size][size],b[size],f[size][2049];

bool mark[100005];

inline

int read(int &in)

inline

int dp(int x)

for(int i=0;i<=18;i++)

for(int j=0;j<=b[i];j++)

f[i][j]=0;

f[0][0]=1;

for(int i=0;i<18;i++)

for(int j=0;j<=b[i];j++)

if(f[i][j])

for(int k=0;k<=b[i+1];k++)

if(((j&k)==0) && ((k&(k>>1))==0))

f[i+1][k]=(f[i][j]+f[i+1][k])%mod;

return f[18][0];

}int main()

bzoj 2734 集合選數

構造矩陣 1 3 9 27 2 6 18 54 4 12 36 108 每個數是上面的數乘2,左面的數乘3。這樣進行狀壓dp就是相鄰的格仔不能選的方案數。如何判斷乙個二進位制數沒有兩個連續的1?x x 1 0 如果有的數沒有出現過,就以它為左上角元素再構造乙個矩陣。這是怎麼想到的?include i...

bzoj 2734 集合選數

written with stackedit.集合論與圖論 這門課程有一道作業題,要求同學們求出 的所有滿足以 下條件的子集 若 x 在該子集中,則 2x 和 3x 不能在該子集中。同學們不喜歡這種具有列舉性 質的題目,於是把它變成了以下問題 對於任意乙個正整數 n leq 100000 如何求出 ...

BZOJ 2734 集合選數(狀態壓縮DP)

題意 給出乙個由1到n的數字組成的集合。定義合法子集為若x在子集中則2x 3x均不能在子集中。求有多少個合法的子集。思路 1 3 9 2 6 18 4 12 36 對於上面的矩陣,我們發現就等價於不選相鄰數字的方案數。因此列舉每個還沒有用到的數字,建立以該數字為左上角的矩陣。接著就是狀態壓縮dp。i...