CF1153F Serval and Bonus Problem [积分,期望]
Posted p-b-p-b
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1153F Serval and Bonus Problem [积分,期望]相关的知识,希望对你有一定的参考价值。
思路
去他的DP,暴力积分多好……
首先发现\(l\)没有用,所以不管它。
然后考虑期望的线性性,可以知道答案就是
\[
\int_0^1 \left[ \sum_i=k^n n\choose i(2x(1-x))^i(1-2x(1-x))^n-i\right]\mathrmdx
\]
我们令
\[
y=2x(1-x)
\]
暴力拆开,答案就是
\[
\int_0^1 \sum_i=K^n n\choose i \sum_j=0^n-i (-1)^j n-i\choose jy^i+j \mathrmd x
\]
也就是
\[
\sum_i=K^n n\choose i \sum_j=0^n-i (-1)^j n-i\choose j 2^i+j\sum_k=0^i+j (-1)^k i+j\choose k \frac 1 i+j+k+1
\]
后面只和\(i+j\)有关,可以预处理。
然后就可以\(O(n^2)\),然后就做完了……
我才不告诉你我没有换元然后硬生生地推出了\(O(n^4)\)的式子呢
我也不会告诉你我还硬生生地把它优化成了\(O(n^3)\)呢
我更不会告诉你我盯着它一下午没推出来呢
代码
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 6000
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) return uniform_int_distribution<T>(l,r)(rng);
templ inline bool chkmax(T &x,T y)return x<y?x=y,1:0;
templ inline bool chkmin(T &x,T y)return x>y?x=y,1:0;
templ inline void read(T& t)
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.')ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
t=(f?-t:t);
template<typename T,typename... Args>inline void read(T& t,Args&... args)read(t); read(args...);
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot()fwrite(__sr,1,__C+1,stdout),__C=-1;
inline void print(register int x)
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
void file()
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
inline void chktime()
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
#ifdef mod
ll ksm(ll x,int y)ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;
ll inv(ll x)return ksm(x,mod-2);
#else
ll ksm(ll x,int y)ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;
#endif
// inline ll mul(ll a,ll b)ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;
using namespace my_std;
ll fac[sz],_fac[sz];
void init()_fac[0]=fac[0]=1;rep(i,1,sz-1) _fac[i]=inv(fac[i]=fac[i-1]*i%mod);
ll C(int n,int m)return n>=m&&m>=0?fac[n]*_fac[m]%mod*_fac[n-m]%mod:0;
int n,K;ll L;
ll f[sz],pow2[sz],Inv[sz];
ll ans;
int main()
file();
read(n,K,L);
init();
rep(i,1,sz-1) pow2[i]=ksm(2,i),Inv[i]=inv(i);
rep(N,1,n) rep(k,0,N) (f[N]+=Inv[N+k+1]*((k&1)?-1ll:1ll)*C(N,k)%mod+mod)%=mod;
rep(i,K,n) rep(j,0,n-i) (ans+=C(n,i)*((j&1)?-1ll:1ll)*C(n-i,j)%mod*pow2[i+j]%mod*f[i+j]%mod+mod)%=mod;
cout<<ans*L%mod;
return 0;
其他做法
这里讲一下标程的神仙DP。
考虑现在线段长度为1,那么可以发现在线段上随机丢一个点\(P\),那么\(P\)被\(k\)条线段覆盖的概率就是要求的答案。
于是我们可以发现只有点之间的相对位置对答案有影响,而在线段上的位置就不重要了。
然后概率再转计数,就是要求\(2n+1\)个点,设出\(n\)个左右端点和一个\(P\),使得满足那个性质的方案数。
然后DP:\(f_i,j,x\)表示前\(i\)个点,有\(j\)个左端点还没被匹配,\(P\)有没有被放下来,的方案数。
最后考虑互换左右端点、给线段编号,答案就是
\[
\fracf_2n+1,0,1n!2^n(2n+1)!
\]
以上是关于CF1153F Serval and Bonus Problem [积分,期望]的主要内容,如果未能解决你的问题,请参考以下文章
CF1153F Serval and Bonus Problem [积分,期望]
Codeforces1153F Serval and Bonus Problem 组合数
CF1153C Serval and Parenthesis Sequence
CF1153C. Serval and Parenthesis Sequence