CF1153F Serval and Bonus Problem
CF1153F Serval and Bonus Problem
官方的解法是O(n2)O(n2)的,这里给出一个O(nlogn)O(nlogn)的做法。
首先对于长度为ll的线段,显然它的答案就是长度为11的线段的答案×l×l,这样做只是为了方便计算。
考虑对于数轴上区间[0,1][0,1]内任意一个点xx,它被一条随机线段覆盖的概率是多少:线段的两个端点都在它左边的概率是x2x2、都在它右边的概率是(1−x)2(1−x)2,那么它被覆盖的概率即为p(x)=1−x2−(1−x)2=2x(1−x)p(x)=1−x2−(1−x)2=2x(1−x)。
那么他被≥k≥k条线段覆盖的概率为f(x)=n∑i=k(ni)p(x)i(1−p(x))n−if(x)=n∑i=k(ni)p(x)i(1−p(x))n−i。
根据定积分的定义就得到区间[0,1][0,1]内被≥k≥k条线段覆盖的长度期望为∫10f(x)dx∫10f(x)dx。
现在我们的问题就是怎么算这个东西了:
∫10f(x)dx=∫10n∑i=k(ni)(2x(1−x))i(1−2x(1−x))n−idx=n∑i=k(ni)∫10(2x(1−x))in−i∑j=0(n−ij)(−2x(1−x))jdx=n∑i=k(ni)n−i∑j=0(n−ij)(−1)j2(i+j)∫10xi+j(1−x)i+jdx
推到这里,就可以把积分去掉了,这是一个Beta Function的形式:记结论吧
B(x,y)=∫10tx−1(1−t)y−1dt=(x−1)!(y−1)!(x+y−1)!
代入得:
∫10f(x)dx=n∑i=k(ni)n−i∑j=0(n−ij)(−1)j2(i+j)((i+j)!)2(2(i+j)+1)!=n!n∑i=kn−i∑j=01i!(−1)jj!2i+j((i+j)!)2(2(i+j)+1)!(n−(i+j))!
令t=i+j,f[i]=1i,g[j]=(−1)jj!,h[t]=2t(t!)2(2t+1)!(n−t)!,考虑枚举t:
∫10f(x)dx=n!n∑t=kh[t]t∑i=kf[i]g[t−i]
这后面就是一个非常显然的卷积式子了,直接FFT即可。
答案记得×l。
//written by newbiechd
#include <cstdio>
#include <cctype>
#include <algorithm>
#define BUF 1000000
using namespace std;
const int N = 100003, yyb = 998244353, Gg = 3, Gi = 332748118;
char buf[BUF], *p1, *p2;
inline char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, BUF, stdin), p1 == p2) ? EOF : *p1++; }
inline int rd() {
register int f = 0;
register char c;
while (!isdigit(c = gc())) {}
do
f = f * 10 + (c ^ 48);
while (isdigit(c = gc()));
return f;
}
int rev[N], G[2][N];
inline int power(int x, int y) {
register int o = 1;
for (; y; y >>= 1, x = 1ll * x * x % yyb)
if (y & 1)
o = 1ll * o * x % yyb;
return o;
}
inline void ntt(int *f, int len, int opt) {
register int i, j, k, x, y, p, q;
for (i = 1; i < len; ++i)
if (i < rev[i])
swap(f[i], f[rev[i]]);
for (i = 1; i < len; i <<= 1) {
p = G[opt][i];
for (j = 0; j < len; j += i << 1)
for (k = 0, q = 1; k < i; ++k, q = 1ll * p * q % yyb)
x = f[j | k], y = 1ll * q * f[i | j | k] % yyb, f[j | k] = (x + y) % yyb, f[i | j | k] = (x - y) % yyb;
}
}
int fac[N], invFac[N], f[N], g[N], h[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
int n = rd(), m = n << 1 | 1, k = rd(), l = rd(), i, len, tmp, ans = 0;
fac[0] = 1;
for (i = 1; i <= m; ++i)
fac[i] = 1ll * fac[i - 1] * i % yyb;
invFac[m] = power(fac[m], yyb - 2);
for (i = m; i; --i)
invFac[i - 1] = 1ll * invFac[i] * i % yyb;
for (i = k; i <= n; ++i)
f[i] = invFac[i];
for (i = 0; i <= n; ++i)
g[i] = i & 1 ? yyb - invFac[i] : invFac[i];
for (len = 1; len <= m; len <<= 1) {}
for (i = 1; i < len; ++i)
rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? len >> 1 : 0);
for (i = 1; i < len; i <<= 1)
G[0][i] = power(Gg, (yyb - 1) / (i << 1)), G[1][i] = power(Gi, (yyb - 1) / (i << 1));
ntt(f, len, 0), ntt(g, len, 0);
for (i = 0; i < len; ++i)
f[i] = 1ll * f[i] * g[i] % yyb;
ntt(f, len, 1), tmp = power(len, yyb - 2);
for (i = 1; i <= n; ++i)
f[i] = 1ll * f[i] * tmp % yyb;
for (i = 1, tmp = 2; i <= n; tmp = (tmp << 1) % yyb, ++i)
h[i] = 1ll * fac[i] * fac[i] % yyb * tmp % yyb * invFac[i << 1 | 1] % yyb * invFac[n - i] % yyb;
for (i = k; i <= n; ++i)
ans = (1ll * f[i] * h[i] % yyb + ans) % yyb;
ans = 1ll * ans * fac[n] % yyb * l % yyb, printf("%d\n", (ans + yyb) % yyb);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 程序员常用高效实用工具推荐,办公效率提升利器!
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)