狀壓妙啊...
本題的主體思路:狀壓+容斥原理(或狀壓+數字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,沒想出來看題解了。假設不考慮記憶化搜尋,這裡可以直接列舉每一位的值來進行計算,這裡可以進行狀壓,利...