Jzoj3170 挑選玩具

2021-08-14 07:43:41 字數 1237 閱讀 6503

abc找到n個箱子,箱子裡裝著一些玩具,一共有m種玩具,編號從1到m,同一種玩具可能出現在多個箱子裡。

abc決定從中選擇一些箱子,把這些箱子中的玩具聚集到一起,必須保證每種玩具至少出現一次。

問abc一共有多少種選擇方案 

(1<=n<=1,000,000,1<=m<=20)

第三次看到這個題了,前兩次都忘了怎麼做了。。。

好的第一眼看上去可以dp做,結果發現只能過50%資料

矩陣明顯不可做,讓後開始考慮數學方法

考慮容斥原理,我們發現可以用總方案減去至少不出現一種玩具的方案數

令f(s)表示選出的方案中,所有元素都在s中的方案數(但是不要求s每個元素都要出現)

令g(s)表示選出的方案中,不包含任何乙個s含有的元素的方案數

那麼可以得到answer=2^n-σg(s)*(-1)^|s|,g(s)=f(~s)

現在考慮如何快速計算f

我們發現如果對於每個s都求出有幾個給出的集合x滿足x∩s=x就可以快速計算得到f(s)=2^x-1

而我們發現,f(s)一定被包含於f(s∪m)

所以可以運用分治法來解決:f[x+m]+=f[x]

最後直接統計即可

#pragma gcc opitmize("o3")

#pragma g++ opitmize("o3")

#include

#include

#include

#define n (1<#define m 1000000007

using

namespace

std;

int c[1

<<20],w[1

<<20],f[1

<<20],p[1

<<20]=,n,m,s=0;

void cdq(int l,int r)

int m=l+r>>1;

cdq(l,m); cdq(m+1,r);

for(int i=l;i<=m;++i) f[i+m-l+1]+=f[i];

}int main()

for(int i=1;i>1]^(i&1);

for(int i=1;i<=n;++i) p[i]=(p[i-1]<<1)%m;

cdq(0,n-1);

for(int i=0;i1]]+1)%m:(s+p[f[n-i-1]]-1)%m;

printf("%d",(s+m)%m);

}

JZOJ3170 挑選玩具

abc找到n個箱子,箱子裡裝著一些玩具,一共有m種玩具,編號從1到m,同一種玩具可能出現在多個箱子裡。abc決定從中選擇一些箱子,把這些箱子中的玩具聚集到一起,必須保證每種玩具至少出現一次。問abc一共有多少種選擇方案。pragma gcc optimize o3 pragma g optimize...

Jzoj3170 挑選玩具

abc找到n個箱子,箱子裡裝著一些玩具,一共有m種玩具,編號從1到m,同一種玩具可能出現在多個箱子裡。abc決定從中選擇一些箱子,把這些箱子中的玩具聚集到一起,必須保證每種玩具至少出現一次。問abc一共有多少種選擇方案 1 n 1,000,000,1 m 20 第三次看到這個題了,前兩次都忘了怎麼做...

JZOJ3170 挑選玩具 分治

有nn 個箱子裝著m m個玩具 乙個玩具可以在多個箱子內 求有多少種選擇箱子的方案使得每種玩具至少有乙個。設f i f i 表示 s1 s i s s 1 s i s 也就是選擇其中一些箱子,會得到乙個玩具集合s s 狀壓後 如果i i完全包含ss,f i f i 就加一。那麼f ma xn 1 i...