苏州国决前集训Day9 模拟测试T2

该博客探讨了如何计算长度为n的整数序列在[1,m]范围内随机分布时,最长连续等子段长度的期望值,并给出了一种O(nlnn)时间复杂度的解决方案。通过前缀和优化和组合数学的方法,计算不同长度子段的方案数,最终求得期望值并模p得到答案。

有一个长度为 nnn 的整数序列,每个元素在 [1,m][1,m][1,m] 中独立均匀随机,求序列的最长连续等子段长度期望长度乘 mnm^nmn,对输入的质数 ppp 取模。

例如,{1,2,2,2,3,3,3,3,2,2,1}\{1,2,2,2,3,3,3,3,2,2,1\}{1,2,2,2,3,3,3,3,2,2,1} 的最长连续等子段长度为 444

1≤n≤3∗105,1≤m≤108,0.99∗109≤p≤1.01∗109,and p is a prime1\leq n\leq 3*10^5,1\leq m\leq 10^8,0.99*10^9\leq p\leq 1.01*10^9,and \ p\ is\ a\ prime1n3105,1m108,0.99109p1.01109,and p is a prime

思路和题解基本一样。

考虑计算 max⁡≤k\max \leq kmaxk 的方案数。

f[i]f[i]f[i] 表示前 iii 个的方案数,显然有转移 f[0]=mm−1,f[i]=∑j=max(0,i−k)i−1f[j]f[0]=\frac{m}{m-1},f[i]=\sum_{j=max(0,i-k)}^{i-1} f[j]f[0]=m1m,f[i]=j=max(0,ik)i1f[j]

前缀和优化即可得到 S[0]=mm−1,S[i]=mS[i−1]+(1−m)S[i−k−1]S[0]=\frac{m}{m-1},S[i]=mS[i-1]+(1-m)S[i-k-1]S[0]=m1m,S[i]=mS[i1]+(1m)S[ik1]

考虑组合意义,枚举跳 k+1k+1k+1 步的次数即可在 O(nln⁡n)O(n\ln n)O(nlnn) 时间内得到答案,至于 f[0]f[0]f[0] 为什么这么奇怪,因为第一步转移应该乘的是 mmm 而不是 m−1m-1m1

#include<bits/stdc++.h>
using namespace std;

const int N=300010;
int n,m,mod,fac[N],inv[N];

int ksm(int x,int t){
	int tot=1;
	while(t){
		if(t&1) tot=1ll*tot*x%mod;
		x=1ll*x*x%mod;
		t/=2;
	}
	return tot;
}

int C(int x,int y){
	return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}

int main(){
	scanf("%d %d %d",&n,&m,&mod);
	fac[0]=1;for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod;
	inv[n]=ksm(fac[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	int ans=ksm(m,n),t=ksm(m,n);
	for(int k=1;k<=n;k++){
		int tot=0;
		for(int a=0;a*(k+1)<=n;a++)
			tot=(tot+1ll*ksm(1+mod-m,a)*ksm(m,n-a*(k+1))%mod*C(n-a*k,a))%mod;
		for(int a=0;a*(k+1)<n;a++)
			tot=(tot+mod-1ll*ksm(1+mod-m,a)*ksm(m,n-1-a*(k+1))%mod*C(n-1-a*k,a)%mod)%mod;
		tot=1ll*tot*ksm(m-1,mod-2)%mod*m%mod;
		ans=(1ll*ans+t+mod-tot)%mod;
	}
	printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值