集合選數 HNOI2012

2022-05-27 13:39:12 字數 1674 閱讀 5165

【問題描述】

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

【輸入格式】

只有一行,其中有乙個正整數 \(n\),\(30\%\)的資料滿足 \(n\le20\), \(100\%\)的資料滿足\(n \le 100000\)。

【輸出格式】

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

第一眼看上去是個組合計數問題。。。然而組合做不了,所以我們考慮dp。

考慮將題目所給的限制條件轉化成乙個矩陣

以從\(1\)開始為例:

這是矩陣 -> \(\begin 1 & 3 & 9 & 27 & ...\\ 2 & 6 & 18 & 54 & ... \\ 4 & 12 & 36 & 108 & ... \\ 8 & 24 & 72 & 216 & ... \\ ... & ... & ... & ... & ... \end

\quad\)

於是乎 原問題就變成了求在這個矩陣裡選一些兩兩不相鄰的數的方案數

由於這些數是指數級增長的,所以在\(100000\)範圍內,粗略估計矩陣的長寬最多也不會超過\(20\),而\(3\)倍增長的列的數目更是不會超過\(11\)。

所以可以想到用狀壓dp 怎麼dp就不說了 注意可以把很多沒必要列舉的狀態跳過,第一次寫的時候被卡tle了。。。

從\(1\)開始的矩陣不一定包含所有數,對於乙個數,如果前面的矩陣都沒有包含它,如\(5, 7, 11\),需要在從這個數開始的矩陣再dp一次,答案就是每次dp出來的部分答案的積。

時間複雜度\(o(\)一秒內\()\)

【**】

#include #include #include #include using namespace std;

typedef long long ll;

const ll mod = 1000000001;

ll n, dp[21][100005], ans = 1;

ll len, len2[1005];

bool vis[100005];

inline void add(ll &x, ll y)

ll solve(ll x)

vis[cur] = 1;

for (int j = 1; ; j++)

vis[cur] = 1;}}

for (int i = 0; i <= len; i++) for (int j = 0; j < (1 << len2[i]); j++) dp[i][j] = 0;

dp[0][0] = 1;

for (int i = 0; i < len; i++) }}

}}

for (int j = 0; j < (1 << len2[len]); j++)

return nowans;

}int main()

}printf("%lld\n", ans);

return 0;

}

~~dp題目太難了 我太蒻了~~

HNOI2012 集合選數

這是題目 大概就是讓你找方案數嘛。開始我還以為是一道規律題,然後有愉快地打了乙個暴搜打表。找了十分鐘沒找出來。www.oeis.org。結果.這是表 半點規律沒有。然後想了想dp,想不出線性或帶log的。最後實在做不出來了,於是問了個大犇。大犇說這道題要用矩形。尼瑪沒在逗我。把題目意思轉換一下嘛。就...

題解 HNOI2012 集合選數

題目傳送門 直接看題面吧。感覺挺水的一道題啊?怎麼評到紫色的啊?考試的時候ljs出了這個題的加強版我就只想出這個思路,然後就爆了。不難發現,我們可以構造矩陣 x 2x 4x 6x 3x 6x 12x 24x 48x 9x 18x 36x 然後實際上就相當於在這個矩陣中選出一些數使得兩兩不相鄰。因為行...

HNOI2012 集合選數 狀壓 dp

求對於正整數 n leq 1e5 的滿足約束條件 若 x 在該子集中,則 2x 和 3x 不在該子集中.的子集個數.是一道很妙的構造 狀壓 dp 題吖.我最開始想這題的時候畫了乙個如下的圖.對於每乙個點,左兒子是它的兩倍,右兒子是它的三倍.約束條件是 連了邊的兩個點是不可以同時選的,也就是只能隔乙個...