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...