生活随笔
收集整理的這篇文章主要介紹了
集训队作业2018: 喂鸽子(min-max容斥)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
小Z是養鴿子的人。一天,小Z給鴿子們喂玉米吃。一共有n只鴿子,小Z每秒會等概率選擇一只鴿子并給他一粒玉米。一只鴿子飽了當且僅當它吃了的玉米粒數量≥k≥k≥k。 小Z想要你告訴他,期望多少秒之后所有的鴿子都飽了。
題解:
min-max容斥枚舉下集合大小,FFT預處理一下系數算min的期望即可。
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std
;const int N
=55, M
=50005, mod
=998244353;
inline int add(int x
,int y
) {return (x
+y
>=mod
) ? (x
+y
-mod
) : (x
+y
);}
inline int dec(int x
,int y
) {return (x
-y
<0) ? (x
-y
+mod
) : (x
-y
);}
inline int mul(int x
,int y
) {return (long long)x
*y
%mod
;}
inline int power(int a
,int b
,int rs
=1) {for(;b
;b
>>=1,a
=mul(a
,a
)) if(b
&1) rs
=mul(rs
,a
); return rs
;}
int x
,y
;
inline void exgcd(int a
,int b
,int &x
,int &y
) {b
? (exgcd(b
,a
%b
,y
,x
),y
-=a
/b
*x
) : (x
=1,y
=0);}
inline int cinv(int a
) {return (exgcd(a
,mod
,x
,y
),(x
+mod
)%mod
);}int n
,k
;
struct combin
{int fac
[M
],ifac
[M
];combin() {fac
[0]=1;for(int i
=1;i
<M
;i
++) fac
[i
]=mul(fac
[i
-1],i
);ifac
[M
-1]=cinv(fac
[M
-1]);for(int i
=M
-2;~i
;i
--) ifac
[i
]=mul(ifac
[i
+1],i
+1);}inline int C(int a
,int b
) {return mul(fac
[a
],mul(ifac
[b
],ifac
[a
-b
]));}
}cb
;namespace FFT
{const int N
=1e6+50, G
=3;int k
,pos
[N
],w
[N
],A
[N
],B
[N
],C
[N
];inline void init(int nn
) {for(k
=1;k
<=nn
;k
<<=1);for(int i
=1;i
<k
;i
++) pos
[i
]=(i
&1) ? ((pos
[i
>>1]>>1)^(k
>>1)) : (pos
[i
>>1]>>1);memset(A
,0,sizeof(int)*k
);memset(B
,0,sizeof(int)*k
);}inline void dft(int *a
) {for(int i
=1;i
<k
;i
++) if(pos
[i
]>i
) swap(a
[pos
[i
]],a
[i
]);for(int bl
=1;bl
<k
;bl
<<=1) {int tl
=bl
<<1, wn
=power(G
,(mod
-1)/tl
);w
[0]=1; for(int i
=1;i
<bl
;i
++) w
[i
]=mul(w
[i
-1],wn
);for(int bg
=0;bg
<k
;bg
+=tl
)for(int j
=0;j
<bl
;j
++) {int &t1
=a
[bg
+j
], &t2
=a
[bg
+j
+bl
], t
=mul(t2
,w
[j
]);t2
=dec(t1
,t
); t1
=add(t1
,t
);}}}inline void mul() {dft(A
), dft(B
);for(int i
=0;i
<k
;i
++) C
[i
]=::mul(A
[i
],B
[i
]);dft(C
); reverse(C
+1,C
+k
);const int inv
=cinv(k
);for(int i
=0;i
<k
;i
++) C
[i
]=::mul(C
[i
],inv
);}
}
struct poly
{vector
<int> a
;poly(int d
=0,int t
=0) {a
.resize(d
+1); a
[d
]=t
;}inline int deg() const {return a
.size()-1;}inline const int& operator[](const int &i
) const {return a
[i
];}inline int& operator[](const int &i
) {return a
[i
];}friend inline poly
operator *(const poly
&a
,const poly
&b
) {poly
c(a
.deg()+b
.deg()); FFT
::init(c
.deg());for(int i
=0;i
<=a
.deg();i
++) FFT
::A
[i
]=a
[i
];for(int i
=0;i
<=b
.deg();i
++) FFT
::B
[i
]=b
[i
];FFT
::mul();for(int i
=0;i
<=c
.deg();i
++) c
[i
]=FFT
::C
[i
];return c
;}friend inline poly
operator +(const poly
&a
,const poly
&b
) {poly
c(max(a
.deg(),b
.deg()));for(int i
=0;i
<=a
.deg();i
++) c
[i
]=add(c
[i
],a
[i
]);for(int i
=0;i
<=b
.deg();i
++) c
[i
]=add(c
[i
],b
[i
]);return c
;}
} f
[N
];int main() {cin
>>n
>>k
;f
[0]=poly(0,1);f
[1]=poly(k
-1,0);for(int i
=0;i
<k
;i
++) f
[1][i
]=cb
.ifac
[i
];for(int i
=2;i
<=n
;i
++) f
[i
]=f
[i
/2]*f
[i
-i
/2];int ans
=0;for(int i
=1;i
<=n
;i
++) {int sum
=1,cof
=1;for(int j
=1;j
<=i
*(k
-1);j
++) {int tot1
=(j
>=k
) ? mul(mul(mul(f
[i
-1][j
-k
],cb
.ifac
[k
-1]),cb
.fac
[j
-1]),i
) : 0;int tot2
=((f
[i
].deg()>=j
) ? mul(f
[i
][j
],cb
.fac
[j
]) : 0);int ff
=mul(tot1
,cinv(add(tot1
,tot2
)));cof
=mul(cof
,dec(1,ff
));sum
=add(sum
,cof
);} sum
=mul(sum
,mul(n
,cinv(i
)));sum
=mul(sum
,cb
.C(n
,i
));if(i
&1) ans
=add(ans
,sum
);else ans
=dec(ans
,sum
);} cout
<<ans
<<'\n';
}
總結
以上是生活随笔為你收集整理的集训队作业2018: 喂鸽子(min-max容斥)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。