CF 449D 題解(狀壓 容斥)

2022-05-25 18:24:07 字數 1636 閱讀 3386

狀壓妙啊...

本題的主體思路:狀壓+容斥原理(或狀壓+數字dp)

記g[i]表示按位與後結果所有位上至少有i個1的方案數

那麼根據容斥原理,ans=g[0]-g[1]+g[2]-g[3]+g[4]...

於是如果我們求出了g,就可以求出ans

可是怎麼求出g呢

我們記f[i]表示a&i==i這樣的a的個數,那麼如果i某一位上為1,則a這一位上也為1

於是我們可以列舉所有可能的結果(0-10^6),然後觀察這個結果是否是某乙個可能結果的子集,如果是的話就累計個數

詳細說一下,就是我首先讀入所有資料,每讀入乙個資料x記錄f[x]++作為初始值,然後不斷更新

在更新的時候,我們首先列舉每一位j,然後列舉1~10^6的所有值i,如果某個值這一位上是1,則更新:

f[i^(1《就是去掉j位的個數加上i

什麼?怎麼證明這樣統計是不重不漏的?

首先,我們是按位列舉的,一開始只有初始讀入的部分有值,剩下的沒有值。那麼,當我們列舉第一位時,我們只會更新由初值去掉第一位所能獲得的所有值

以此類推,當我們更新第二位時,我們只會更新初值去掉前兩位和初值只去掉第二位能獲得的所有值

也就是說,我們在更新每一位時,都不會產生重複的狀態,都是原來的狀態+這一位,所以是不重的,而由於這樣的列舉能夠遍歷所有數字的組合,所以也是不漏的

好,我們處理出了f,接下來?

我們可以列舉所有結果,統計他有幾位上是1,那麼如果有1位上是1,就會對g[1]產生貢獻,等等,以此類推

然後我們再考慮,產生多少貢獻?

我們會發現,如果這個結果對應的數有k個,那麼答案應為2^k-1(即每個數都有選或不選兩種狀態,但不能全不選)

所以他產生的貢獻就是2^k-1

什麼?這種方法的正確性何在?

首先,根據容斥原理,答案的正確性是很顯然的

那麼我們只需證明g求解的正確性即可

首先回顧一下g的定義:「至少」包含i個1的取法的方案數

也就是說,我所找出的東西數字中1的個數只需》=i即可

那這個是很顯然能夠保證的

於是為什麼不重呢?

由於每個結果互不相同,而我們最後事實上是按結果取的,所以每一種取法都是互不相同的,保證了正確性。

最後**:

#include #include 

#define ll long long

#define mode 1000000007

#define maxx 1000000ll v[

1000005

];ll dp[

1000005

];ll f[

25];

intn;

intmain()

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

for(int j=0;j<=20;j++)}}

ll ans=0

;

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

}f[cnt]+=((v[dp[i]]-1)%mode+mode)%mode;

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

else

}printf(

"%i64d\n

",(ans%mode+mode)%mode);

return0;

}

bozj2669(容斥 狀壓dp)

一張圖最多8個區域性最小值。dp i j 表示正在填從小到大第i個數,區域性最小值所在的位置已被填的情況為j時的方案數 p i 為區域性最小值所在的位置已被填的情況為j時,所有可以填數的位置數。x為沒被填的區域性最小值,x的周圍都不能填,如果填了x就不是區域性最小值了!所以才會存在可以填數的位置數 ...

bzoj 3812 狀壓dp 容斥原理

題意 乙個n個點m條邊的有向強連通圖,去掉一些邊使其仍然強連通,求方案數。以前做的題,現在看已經不知道自己在寫什麼了。寫一點題解。如果乙個圖縮點後變成乙個有多個點的dag,那麼這玩意一定不連通。設f i 表示拆邊使集合i強連通的方案數,g i 表示i集合的點縮點後成為奇數個彼此沒有邊的點的方案數,p...

CF 55D數字dp 狀壓

cf 55d數字dp 狀壓 求出區間 l,r 中的所有beautiful number的數目,如果乙個數x可以被它各個數字上的非零數整除,那它就是beautiful number。很巧妙的一道數字dp,沒想出來看題解了。假設不考慮記憶化搜尋,這裡可以直接列舉每一位的值來進行計算,這裡可以進行狀壓,利...