[Luogu3600] 随机数生成器 [概率期望&动态规划 & 拉格朗日插值&离散微积分]

[ L i n k \frak{Link} Link]


E [ a n s = max ⁡ 1 ≤ i ≤ q ( min ⁡ l i ≤ j ≤ r i a j ) ] \rm{E}\left[ans=\max\limits_{1\le i\le q}\left(\min\limits_{l_i\le j\le r_i}a_j\right)\right] E[ans=1iqmax(lijriminaj)] ,其中 a j a_j aj [ 1 , x ] [1,x] [1,x] 中的随机一个整数 。

模质数 666623333 666623333 666623333


显然有:

E ( a n s ) = ∑ k ∈ [ 1 , x ] k Pr ⁡ ( a n s = k ) = ∑ k ∈ [ 1 , x ] k [ Pr ⁡ ( a n s ≤ k ) − Pr ⁡ ( a n s ≤ k − 1 ) ] \rm E(ans)=\sum\limits_{k\in[1,x]} k\Pr(ans=k)=\sum\limits_{k\in[1,x]} k\left[\Pr(ans\le k)-\Pr(ans\le k-1)\right] E(ans)=k[1,x]kPr(ans=k)=k[1,x]k[Pr(ansk)Pr(ansk1)]


Pre

首先把区间按照左端点排一排。

只需要求 Pr ⁡ ( a n s ≤ k ) , k ∈ [ 1 , x ] \rm\Pr(ans\le k),k\in[1,x] Pr(ansk),k[1,x]
有点难搞:考虑到这东西的意义是询问区间的最小值的最大值不大于 k k k
也就是:询问区间的最小值都不大于 k k k
考虑设状态 f ( i ) f(i) f(i) 表示处理到第 i i i 个区间都满足条件的概率?

毕竟不好重复计算单个点,所以我们尽量考虑让 i i i 表示位置。
那么考虑令 f ( i ) f(i) f(i) 表示所有右端点不大于 i i i 的区间都满足条件的概率。

那怎么转移啊?
就得考虑 i i i 有没有被哪些区间覆盖,然后因为区间可能重叠计算又困难了blabla
区间有重叠不好搞,所以我们考虑把区间和点互换。

(容易注意到,上面已经钦定了 k k k 是要被枚举的。)


O(n2)

假如排序后右端点单调那么一个点能够覆盖一个区间的区间。
现在右端点不单调,考虑能不能让它单调。不单调是因为有区间覆盖的情况。
对于一个覆盖了别的区间的区间,它是没用的,可以被舍去。(显然地
那么、经过进一步预处理之后,每个点对应的区间可以覆盖的区间是连续的一段区间。
对每个点 i i i 记录其能够覆盖的区间 L i ∼ R i L_i\sim R_i LiRi

现在变成了选择点覆盖所有区间。
考虑:选择了点 i i i 使所有右端点不大于 i i i 的区间都被覆盖的概率 f ( i ) f(i) f(i)
并且,“点覆盖区间” 的意义应当是 “点是区间的最小值点” ,我们需要控制此时点值不大于 k k k

所以我们考虑:“选择了点” 指 “点值不大于 i i i “。转移显然 f ( n ) = [ [ l i = 1 ] + ∑ i &lt; n ∣ R i ≥ L n − 1 f ( i ) ( 1 − k x ) i ] ⋅ ( 1 − k x ) n − 1 ⋅ k x \displaystyle{{f(n)=\left[[l_i=1]+\sum\limits_{i&lt;n|R_i\ge L_n-1}\cfrac{f(i)}{\left(1-\frac{k}{x}\right)^{i}}\right]\cdot\left(1-\frac{k}{x}\right)^{n-1}\cdot\frac{k}{x}}} f(n)=[li=1]+i<nRiLn1(1xk)if(i)(1xk)n1xk

根据处理方式不同可能代码差别比较大。
把中间的指数拆开然后预处理前缀和以及幂。复杂度 O ( n 2 ) O(n^2) O(n2)

因为懒得调(??)所以下面的代码其实可以被插,(我没处理有点不被区间覆盖的情况)
正确的做法可以概率转计数就很容易求;或者仍然按照同样的思路代码写好一点

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define adjust(x) (((x%p)+p)%p)
const long long p = 666623333;
const int MAXN = 2005;
void exgcd(long long a, long long b, long long &d, long long &x, long long &y)
{
	if (!b) { d = a; x = 1; y = 0;}
	else { exgcd(b, a%b, d, y, x); y -= x * (a / b);}
}
long long inv(long long a)
{
	long long d, x, y;
	exgcd(a, p, d, x, y);
	return ((x % p) + p) % p;
}
bool cmp(const pair<int,int> &a, const pair<int,int> &b)
{
	if (a.first==b.first)return a.second>b.second;
	return a.first<b.first;
}

pair<int,int> seq[MAXN];
int n, x, q, r[MAXN], l[MAXN];
long long pre[MAXN], nre[MAXN], sum[MAXN], f[MAXN];
long long inx, tem1, tem2, nem2;
long long ans, cur, las;

int main()
{
	scanf("%d%d%d", &n, &x, &q);
	inx = inv(x);
	for (int i = 1; i <= q; ++i) scanf("%d%d", &seq[i].first, &seq[i].second);
	sort(seq + 1, seq + 1 + q, cmp);
	for (int i = q; i > 0; --i) if (i < q && seq[i+1].second <= seq[i].second) seq[i] = seq[i+1];
	q = unique(seq + 1, seq + 1 + q) - seq - 1;
	for (int ptl = 1, ptr = 0, i = 1; i <= n; ++i)
	{
		while (ptr<q && seq[ptr+1].first==i) ++ptr;
		while (ptl<=q && seq[ptl].second<i) ++ptl;
		r[i] = ptr, l[i] = ptl;
	}
	for (int k = 1; k <= x; ++k)
	{
		tem1 = 1ll * k * inx % p;
		tem2 = adjust(1ll - tem1);
		nem2 = inv(tem2);
		
		pre[0] = nre[0] = 1;
		for (int i = 1; i <= n; ++i) pre[i] = pre[i-1] * tem2 % p;
		for (int i = 1; i <= n; ++i) nre[i] = nre[i-1] * nem2 % p;
		
		cur = 0;
		for (int i = 1, j = 0; i <= n; ++i)
		{
			while (j < i && r[j] < l[i]-1) ++j;
			
			f[i] = adjust(sum[i-1] - sum[(j<1?0:j-1)]) * pre[i-1] % p;
			if (l[i] == 1) f[i] = (f[i] + pre[i-1]) % p;
			f[i] = f[i] * tem1 % p;
			
			sum[i] = (sum[i-1] + f[i] * nre[i] % p) % p;
			if (r[i] == q) cur += f[i], cur %= p;
		}
		
		ans += 1ll * k * adjust(cur - las) % p;
		ans %= p;
		las = cur;
	}
	printf("%lld", ans);
	return 0;
}

x≤107

我大概能够想到的办法就是
首先 Pr ⁡ \Pr Pr 可以用 k k k 表示
然后 E ( a n s ) \rm E(ans) E(ans) 可以表示为多个 Pr ⁡ \Pr Pr 的和,也就是关于 k k k 的多项式在一段离散区间内值的和


无关

然后我飘了

这是前缀和,也可以说是“离散积分”一类的东西,实际上就是 ∑ \sum 取代 ∫ \int
注意为了方便离散积分 ∑ a b \sum_a^b ab 表示对 [ a , b ) [a,b) [a,b) 求和。
那么我们仍然考虑微积分基本定理,有没有什么东西离散的时候类似导数?就是差啦
定义差分算子 Δ \Delta Δ

我们知道一个简单的导数 ( x k ) ′ = k x k − 1 (x^k)&#x27;=kx^{k-1} (xk)=kxk1
离散的时候类似地有 Δ ( x k ‾ ) = ( x + 1 ) k ‾ − x k ‾ = k x k − 1 ‾ \Delta(x^{\underline{k}})=(x+1)^{\underline{k}}-x^{\underline{k}}=kx^{\underline{k-1}} Δ(xk)=(x+1)kxk=kxk1
另外, Δ ( k x ) = ( k − 1 ) k x \Delta(k^x)=(k-1)k^x Δ(kx)=(k1)kx
特殊地, Δ ( 2 x ) = 2 x \Delta(2^x)=2^x Δ(2x)=2x

(PS:用第二类斯特林数可以把幂级数和下降幂相互转换。
用第一类斯特林数也有 x k ‾ = ∑ i = 0 k [ k i ] x i x^{\underline k}=\sum\limits_{i=0}^k[{k\atop i}]x^i xk=i=0k[ik]xi

定义位移算子 E = f ( x + 1 ) f ( x ) E=\frac{f(x+1)}{f(x)} E=f(x)f(x+1) 有分部积分法
Δ [ f ( x ) ⋅ g ( x ) ] = E Δ f ( x ) ⋅ g ( x ) + f ( x ) ⋅ Δ g ( x ) \Delta[f(x)\cdot g(x)]=E\Delta f(x)\cdot g(x)+f(x)\cdot\Delta g(x) Δ[f(x)g(x)]=EΔf(x)g(x)+f(x)Δg(x)

定义 n n n 阶差分 Δ n f = Δ ( Δ n − 1 f ) \Delta^nf=\Delta(\Delta^{n-1}f) Δnf=Δ(Δn1f) ,特殊地有 Δ 0 f = f \Delta^0 f=f Δ0f=f
类似于麦克劳林展开,对于 k k k 阶多项式 f f f 我们有 f ( n ) = ∑ i = 0 k Δ i f ( 0 ) ∗ n i ‾ i ! f(n)= \sum\limits_{i=0}^{k}\Delta^{i}f(0)*\frac{n^{\underline{i}}}{i!} f(n)=i=0kΔif(0)i!ni

利用这个,我们可以秒一些求和,比如 ∑ i = 1 n i k ‾ = ∑ 1 n + 1 i k ‾ δ i = x k + 1 ‾ k + 1 ∣ 1 n + 1 \sum\limits_{i=1}^ni^{\underline{k}}=\sum_{1}^{n+1}i^{\underline{k}}\delta i=\frac{x^{\underline{k+1}}}{k+1}|^{n+1}_1 i=1nik=1n+1ikδi=k+1xk+11n+1
不用离散微积分的话貌似要先用第二类斯特林数把它转化为幂级数,再二项式反演。

至于通常幂也可以用第二类斯特林数 x k = ∑ i = 0 x { k i } x i ‾ x^k=\sum\limits_{i=0}^x\{{k\atop i}\}x^{\underline i} xk=i=0x{ik}xi 来搞
然后可以快乐自然数幂和 O ( k log ⁡ k ) O(k\log k) O(klogk)
另外,根据差分表法自然数幂和可以展开成 k + 1 k+1 k+1 次多项式, O ( n ) O(n) O(n) 拉格朗日插值可解。
(常数巨大,如果没有卡就带个 l o g log log 吧)

另外, Δ n f ( x ) = ∑ k = 0 n ( n k ) ( − 1 ) n − k f ( x + k ) \Delta^n f(x)=\sum\limits_{k=0}^{n} \binom{n}{k} (-1)^{n-k} f(x+k) Δnf(x)=k=0n(kn)(1)nkf(x+k)

另另外,牛顿级数: k k k 阶多项式 f ( n ) f(n) f(n) 可以被唯一分解为 ∑ i = 0 k c i ( x i ) \sum\limits_{i=0}^k c_i{x\choose i} i=0kci(ix) 并且有 Δ n f ( 0 ) = c i \Delta^nf(0)=c_i Δnf(0)=ci
然后可以求和也可以还原系数,复杂度都是 O ( k 2 ) O(k^2) O(k2)
主要是得到了一个比较通用的快速单点求值方法。 O ( k ) O(k) O(k)

求自然数幂和针对性的方法是利用伯努利数


x≤107

虽然口胡了一通,
但是我并不是很明白.jpg
等一个大佬接手

“电子文档处理”是一个文档批量处理、批量格式转换工具;help和chm帮助文件快速制作软件;电子书批量制作工具;批量chm反编译工具;内码转换、索引生成、批量改名软件。支持子目录及光盘直接操作,自动化程度高。欢迎使用“电子文档处理”这一简单快捷的chm制作软件、help制作软件,“易上手”的特点让你自己动手轻松制作chm文件和help文件。 主要产品功能: 文本文件批量转换为帮助文件(txt2chm和Htm2chm:chm帮助文件制作软件,txt2help:help帮助文件制作工具),用户无须学习任何指令就可以快速地制作自己的电子书或chm帮助文件; 网页文件转为文本文件(htm2txt); 纯文本文件批量转换为网页文件,且自动生成上下文链接及目录(txt2html); 纯文本文件转换为微软网页帮助文件(htm2chm:chm帮助文件制作工具); VB源文件转为网页文件(vb2html); 索引生成(index maker); 繁简体互相转换(gb2big,big52gb); 文件改名(file renamer)。 NAME:DIGERATI S/N:7265676E616D65 注册方法如下: 1、安装程序完成后,把注册文件 ews69181591fd96.crc 复制到“etextwizard”程序所在的目录下,注意必须在相同的目录下,请不要更改这个注册文件的文件名或文件内容。 注册成功的标志: 1、菜单上明显的“注册”项消失了; 2、“购买”按钮消失了,“关于”菜单下出现了“本软件注册给:"DIGERATI"的字样 注册文件 ews69181591fd96.crc 是采用特殊算法生成的,请千万不要修改注册文件里面的内容或文件名,这点非常重要!请务必按说明执行注册...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值