也许更好的阅读体验

\(\mathcal{Description}\)

给你一个长度为\(n\)的数组\(a\)

你会得到 \(q\) 条指令, 分两种:

  • \(1\ l\ r\ w\) 表示把 \(l, l + 1,\ldots r\) 这段区间的每一个数 \(+w\).
  • \(2\ l\ r\) 表示询问 \(l, l + 1, \ldots r\) 这段区间每个子序列方差之和.

对于每个询问输出一行表示答案

答案对\(998244353\)取模

\(n,q\leq 10^5\\
0\leq a_i,w<998244353\)

\(\mathcal{Solution}\)

方差的定义

对一个序列\(a_1,a_2,\ldots,a_n\),设其平均数为\(\overline a=\dfrac{\sum\limits a_i}{n}\),方差\(s^2=\dfrac{\sum\limits \left(a_i-\overline a\right)^2}{n}\)

前置知识

\(\left(a_1+a_2+\ldots+a_n\right)^2=a_1^2+a_2^2+\ldots+a_n^2+2\sum\limits_{i!=j} a_ia_j\)

\(s^2=\dfrac{\sum\limits \left(a_i-\overline a\right)^2}{n}=\dfrac{\sum \left(a_i^2-2a_i\overline a+\overline a^2\right)}{n}=\dfrac{\sum a_i^2-2n\overline a^2+n\overline a}{n}=\dfrac{\sum a_i^2-n\overline a^2}{n}=\dfrac{\sum a_i^2-\dfrac{\sum a_i^2+2\sum\limits_{i!=j}a_ia_j}{n}}{n}\)

把式子提出来重写一遍

\(s^2=\dfrac{\sum a_i^2-\dfrac{\sum a_i^2+2\sum\limits_{i!=j}a_ia_j}{n}}{n}\)

于是可以计算上面的\(a_i,a_ia_j\)出现次数(贡献的系数),考虑一个长度为\(n\)的区间,其子序列长度可以是\(len=1,2,\ldots,n\)

考虑\(a_i\)一定被选,剩下\(n-1\)个数中要选\(len-1\)个数出来,类似这样考虑即可

显然对于每个区间内的数,其系数是一样的

设\(f_n\)表示长度为\(n\)的区间里的\(a_i^2\)的系数

则有

\(\begin{aligned}f_n&=\sum\limits_{i=1}^n\begin{pmatrix}n-1\\i-1\end{pmatrix}\dfrac{1-\dfrac{1}{i}}{i}\\
&=\sum\limits_{i=1}^n\begin{pmatrix}n-1\\i-1\end{pmatrix}\dfrac{i-1}{i^2}\\&= \sum\limits_{i=1}^n\dfrac{\left(n-1\right)!\ \left(i-1\right)}{\left(n-i\right)!\left(i-1\right)!\ i^2}\\&=\left(n-1\right)!\sum\limits_{i=1}^n\dfrac{1}{\left(n-i\right)!\left(i-2\right)!i^2}\\&=\left(n-1\right)!\sum\limits_{i+j=n}^n\dfrac{1}{\left(i-2\right)!i^2}\dfrac{1}{j!}\end{aligned}\)

注意最后\(i\geq 2\)

可以发现这是一个卷积的形式,可以\(nlogn\)算出来

设\(g_n\)表示长度为\(n\)的区间里的\(2a_ia_j\)的系数

则有

\(g_n=\sum\limits_{i=2}^n\begin{pmatrix}n-2\\i-2\end{pmatrix}\dfrac{-1}{i^2}\)

同理可推得

\(g_n=-\left(n-2\right)!\sum\limits_{i+j=n}^n\dfrac{1}{\left(i-2\right)!i^2}\dfrac{1}{j!}\)

注意\(i\geq 2\)

\(f_n,g_n\)只有前面的系数不同,把后面弄出来即可

另外,对于一个区间,用线段树维护维护一下\(\sum a_i\)和\(\sum a_i^2\)

\(\mathcal{Code}\)

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年10月03日 星期四 09时36分57秒
*******************************/
#include <cstdio>
#include <fstream>
using namespace std;
const int maxn = 1000006;
const int maxt = 1000006;
const int mod = 998244353;
const int gn = 3;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
inline int add (int &x,int y){ return x=((x+y)%mod+mod)%mod;}
inline int mul (int x,int y){ return 1ll*x*y%mod;}
int n,q,id,ans;
int a[maxn],rev[maxn],inv[maxn],fac[maxn],ifac[maxn];
int f[maxn],g[maxn];
//{{{SegmentTree
struct SegmentTree{
//0 -> x^2
//1 -> x
//{{{defination
#define cl (k<<1)
#define cr (k<<1|1)
#define lm (lt[k]+rt[k])/2
#define rm (lt[k]+rt[k])/2+1
#define val0(x) val[x][0]
#define val1(x) val[x][1]
#define lazy0(x) lazy[x][0]
#define lazy1(x) lazy[x][1]
#define len(x) (rt[x]-lt[x]+1)
int lt[maxt],rt[maxt],val[maxt][2],lazy[maxt][2];
//}}}
//{{{build
void build (int l,int r,int k=1)
{
lt[k]=l,rt[k]=r;
if (l==r) return val0(k)=mul(a[l],a[l]),val1(k)=a[l],void();
build(l,lm,cl);
build(rm,r,cr);
val0(k)=(val0(cl)+val0(cr))%mod;
val1(k)=(val1(cl)+val1(cr))%mod;
}
//}}}
//{{{pushdowna
void pushdowna (const int &k)
{
add(lazy1(cl),lazy1(k));
add(lazy1(cr),lazy1(k));
add(val1(cl),mul(len(cl),lazy1(k)));
add(val1(cr),mul(len(cr),lazy1(k)));
lazy1(k)=0;
}
//}}}
//{{{pushdowns
void pushdowns (const int &k)
{
add(lazy0(cl),lazy0(k));
add(lazy0(cr),lazy0(k));
add(val0(cl),mul(len(cl),mul(lazy0(k),lazy0(k))));
add(val0(cr),mul(len(cr),mul(lazy0(k),lazy0(k))));
add(val0(cl),mul(mul(lazy0(k),2),val1(cl)));
add(val0(cr),mul(mul(lazy0(k),2),val1(cr)));
lazy0(k)=0;
}
//}}}
//{{{modifys
void modifys (const int l,const int r,const int v,const int &k=1)
{
if (lt[k]>=l&&rt[k]<=r){
add(val0(k),mul(len(k),mul(v,v)));
add(val0(k),mul(mul(v,2),val1(k)));
add(lazy0(k),v);
return;
}
if (lazy0(k)) pushdowns(k);
if (lazy1(k)) pushdowna(k);
if (lm>=l) modifys(l,r,v,cl);
if (rm<=r) modifys(l,r,v,cr);
val0(k)=(val0(cl)+val0(cr))%mod;
val1(k)=(val1(cl)+val1(cr))%mod;
}
//}}}
//{{{modifya
void modifya (const int &l,const int &r,const int &v,const int &k=1)
{
if (lt[k]>=l&&rt[k]<=r){
add(val1(k),mul(len(k),v));
add(lazy1(k),v);
return;
}
if (lazy0(k)) pushdowns(k);
if (lazy1(k)) pushdowna(k);
if (lm>=l) modifya(l,r,v,cl);
if (rm<=r) modifya(l,r,v,cr);
val0(k)=(val0(cl)+val0(cr))%mod;
val1(k)=(val1(cl)+val1(cr))%mod;
}
//}}}
//{{{query
int query (const int l,const int r,const bool opt,const int &k=1)
{
if (lt[k]>=l&&rt[k]<=r) return val[k][opt];
if (lazy0(k)) pushdowns(k);
if (lazy1(k)) pushdowna(k);
int res=0;
if (lm>=l) add(res,query(l,r,opt,cl));
if (rm<=r) add(res,query(l,r,opt,cr));
return res;
}
//}}}
}ST;
//}}}
//{{{ksm
int ksm (int a,int b)
{
int s=1;
for (;b;b>>=1,a=1ll*a*a%mod)
if (b&1) s=1ll*s*a%mod;
return s;
}
//}}}
//{{{get_rev
int get_rev (int len)//the maximum power of x is len!!!! not the length
{
int lim=1,bit=0;
while (lim<=len) lim<<=1,++bit;
for (int i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
return lim;
}
//}}}
//{{{NTT
void NTT (int *a,int len,int type)
{
for (int i=0;i<=len-1;++i)
if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=1;i<len;i<<=1){
int wn=ksm(gn,(mod-1)/(i*2));
if (type==-1) wn=ksm(wn,mod-2);
for (int j=0;j<len;j+=(i<<1)){
int w=1;
for (int k=0;k<i;++k){
int u=a[j+k],t=1ll*w*a[j+k+i]%mod;
a[j+k]=1ll*(u+t)%mod;
a[j+k+i]=1ll*(u-t+mod)%mod;
w=1ll*w*wn%mod;
}
}
}
if (type==-1){
int inv=ksm(len,mod-2);
for (int i=0;i<=len-1;++i) a[i]=1ll*a[i]*inv%mod;
}
}
//}}}
//{{{init
void init ()
{
fac[0]=ifac[0]=inv[1]=1;
for (int i=2;i<=n+2;++i) inv[i]=(-1ll*mod/i*inv[mod%i]%mod+mod)%mod;
for (int i=1;i<=n+2;++i){
fac[i]=mul(fac[i-1],i);
ifac[i]=mul(ifac[i-1],inv[i]);
}
for (int i=0;i<=n;++i){
f[i]=ifac[i];
g[i]=i<=1?0:mul(mul(inv[i],inv[i]),ifac[i-2]);
}
int len=get_rev(n<<1);
NTT(f,len,1),NTT(g,len,1);
for (int i=0;i<len;++i) f[i]=mul(f[i],g[i]);
NTT(f,len,-1);
for (int i=0;i<=n;++i){
g[i]=0;
if (i>1) add(g[i],-mul(fac[i-2],f[i])),f[i]=mul(fac[i-1],f[i]);
}
}
//}}}
int main ()
{
cin>>n>>q>>id;
for (int i=1;i<=n;++i) cin>>a[i];
init();
ST.build(1,n);
while (q--){
int opt,l,r;
cin>>opt>>l>>r;
if (opt==1){
int x;
cin>>x;
ST.modifys(l,r,x);
ST.modifya(l,r,x);
}
else{
int s1=ST.query(l,r,0),s2=ST.query(l,r,1),len=r-l+1;
s2=mul(s2,s2);
add(s2,-s1);
int ans1=mul(s1,f[len]),ans2=mul(s2,g[len]);
add(ans1,ans2);
printf("%d\n",ans1);
}
}
return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正

如您喜欢的话不妨点个赞收藏一下吧

序列方差[NTT]的更多相关文章

  1. 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数

    [题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...

  2. 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

    [BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...

  3. BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Statu ...

  4. [SDOI2015]序列统计(NTT+求原根)

    题目 [SDOI2015]序列统计 挺好的题!!! 做法 \(f[i][j]\)为第\(i\)个数前缀积在模\(M\)意义下为\(j\) 显然是可以快速幂的:\[f[2*i][j]=\sum\limi ...

  5. BZOJ3992: [SDOI2015]序列统计(NTT 原根 生成函数)

    题意 题目链接 给出大小为\(S\)的集合,从中选出\(N\)个数,满足他们的乘积\(\% M = X\)的方案数 Sol 神仙题Orz 首先不难列出最裸的dp方程,设\(f[i][j]\)表示选了\ ...

  6. bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...

  7. bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...

  8. bzoj 3992: [SDOI2015]序列统计 NTT+原根

    今天开始学习丧心病狂的多项式qaq......    . code: #include <bits/stdc++.h> #define ll long long #define setIO ...

  9. 51nod 1514 美妙的序列 分治NTT + 容斥

    Code: #include<bits/stdc++.h> #define ll long long #define mod 998244353 #define maxn 400000 # ...

随机推荐

  1. sass - for循环写法

    如要设置多个li的动画延迟时间时 注:这里选择器要加#{}才行 不然就会编译成: 6.7. 插值语句 #{} (Interpolation: #{}) 通过 #{} 插值语句可以在选择器或属性名中使用 ...

  2. 关于微信手机端IOS系统中input输入框无法输入的问题

    如果网站不需要阻止用户的选择内容的行为就可以使用如下样式: * { -webkit-user-select: text; -user-select: text;}另一种方式: *: not(input ...

  3. flutter Radio单选框

    单选框,允许用户从一组中选择一个选项. import 'package:flutter/material.dart'; class RadioDemo extends StatefulWidget { ...

  4. spark ml pipeline构建机器学习任务

    一.关于spark ml pipeline与机器学习一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的流 ...

  5. 关于TCP粘包和拆包的终极解答

    关于TCP粘包和拆包的终极解答 程序员行业有一些奇怪的错误的观点(误解),这些误解非常之流行,而且持有这些错误观点的人经常言之凿凿,打死也不相信自己有错,实在让人啼笑皆非.究其原因,还是因为这些错误观 ...

  6. python3以post方式提交数据

    # !/usr/bin/python # encoding:utf-8 import requests #下面替换成您的数据 postdata={'name':'xiaochong'} r=reque ...

  7. osg塔吊模拟-20191026

    在osg中模拟塔吊群作业

  8. RabbitMQ 清除全部队列及消息

    前言 安装RabbitMQ后可访问:http://{rabbitmq安装IP}:15672使用(默认的是帐号guest,密码guest.此账号只能在安装RabbitMQ的机器上登录,无法远程访问登录. ...

  9. 宣化上人:大佛顶首楞严经四种清净明诲浅释(2-3) -------------------------------------------------------------------------------- (转自学佛网:http://www.xuefo.net/nr/article23/230612.html)

    大佛顶首楞严经四种清净明诲浅释(2-3) 唐天竺·沙门般剌密帝译 宣化上人主讲 一九八三年四月十七日晚讲于万佛圣城 欲摄其心入三摩地:这种邪师说法,在末法的时候像恒河沙这么多:可是我想在这时候,令一切 ...

  10. SQL Server 2014 清除用户名和密码

    网上找来找去都是SQL Server 2008版本或者以前版本的... 后来:http://stackoverflow.com/questions/349668/removing-the-rememb ...