ARC111F Do you like query problems? 题解
目录
题目描述
一个长为 的序列 ,初始全为 。
接下来 次操作:
1 l r v
:对 ,令 。2 l r v
:对 ,令 。3 l r
:输出 。
其中 。
你需要统计所有 个操作序列中,所有输出答案的和。
数据范围
- 。
时间限制 ,空间限制 。
分析
显然拆成每个位置算贡献。
记 ,先算期望,最后乘上 即可。
,记 为经过 次操作后, 的概率, 为区间 包含 的概率。
- 如果 没有落在 内,显然 不会变化。
- 如果 落在 内,综合前两种操作,有 种操作方法可以将 分别变成 ,另 种方法 不会变化。当然,如果操作为询问, 也不会变化。
转移方程为:
初始值 ,统计答案枚举询问位置:
于是我们得到了一个的做法。
观察上面的转移方程,发现 的地位相等。
重新设计状态, 表示经过 次操作后, 的概率。则 , 的概率为 。
转移方程:
第 次操作对答案的贡献:
一阶线性递推,并且转移系数与 无关,矩阵快速幂优化:
时间复杂度 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+5,mod=998244353;
int m,n,q,t,res;
struct mat
{
int v[3][3];
};
mat operator*(const mat &a,const mat &b)
{
static mat c;
for(int i=0;i<=2;i++)
for(int j=0;j<=2;j++)
{
c.v[i][j]=0;
for(int k=0;k<=2;k++) c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%mod;
}
return c;
}
int qpow(int a,int k)
{
int res=1;
while(k)
{
if(k&1) res=res*a%mod;
a=a*a%mod,k>>=1;
}
return res;
}
mat qpow(mat a,int k)
{
mat res={1,0,1,0,0,0,0,0,0};
while(k)
{
if(k&1) res=res*a;
a=a*a,k>>=1;
}
return res;
}
signed main()
{
scanf("%lld%lld%lld",&n,&m,&q),t=(2*m+1)*n*(n+1)/2%mod;
for(int j=1,tmp=m*(mod+1)/2%mod;j<=n;j++)
{
int p=j*(n+1-j)%mod*qpow(t,mod-2)%mod;
mat mul={(1-p*m)%mod,-p*tmp%mod,0,0,1,0,p,p*tmp%mod,1};
res=(res+qpow(mul,q).v[0][1])%mod;
/**for(int i=1,x=1;i<=q;i++)
{
res=(res+p*tmp%mod*(1-x))%mod;
x=((1-p*m)%mod*x+p)%mod;
}**/
}
printf("%lld\n",(res+mod)*qpow(t,q)%mod);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17124435.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通