求和
给定数列 (a_1...a_n) 及 (x_0)。
满足
[f_{i.j}=egin{cases}
a_i & j=0,ileq n\
x_0 & j=0,i=n+1\
f_{i,j-1}+f_{i-1,j-1} & 0 < i,j leq n+1,j < i\
0 & ileq j
end{cases}
]
求
[sum_{i=0}^{n+1}sum_{j=0}^{n+1}f_{i,j}
]
但这样太水了
于是给出 (m) 个操作,每次将 (a_ldots a_r~(0le l,r le n)) 加 (p),对于每个操作,输出答案。
特别地,若 (0) 在 (ldots r) 范围内,我们认为 (x_0) 也加 (p)。
另外,在读入 (m) 个操作前,你也应该输出答案。
由于答案可能过大,输出答案对 (1234567891) 取模的结果。
(n,m leq 10^5)。
题解
https://www.luogu.com.cn/blog/user7035/solution-p5178
大概可以画出这样的图:
行列 | 0 | 1 | 2 | 3 | ... | n-1 | n |
---|---|---|---|---|---|---|---|
1 | a1 | 0 | 0 | 0 | ... | 0 | 0 |
2 | a2 | f2,1 | 0 | 0 | ... | 0 | 0 |
3 | a3 | f3,1 | f3,2 | 0 | ... | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... |
n | an | fn,1 | fn,2 | fn,3 | ... | fn,n-1 | 0 |
n+1 | an | fn+1,1 | fn+1,2 | fn+1,3 | ... | fn+1,n-1 | fn+1,n |
每个点都对右方和右下方的元素有贡献。那么
[f_{i,j}=egin{cases}
0 & ileq j\
sum_{k=0}^jinom{j}{k}a_{i-k} & i>j
end{cases}
]
开始大力推式子。
[ans=sum_{i=1}^{n+1}sum_{j=0}^{i-1}f_{i,j}=sum_{i=1}^{n+1}sum_{j=0}^{i-1}sum_{k=0}^jinom{j}{k}a_{i-k}
]
在这道题里面我们显然是要对组合数进行操作来减少求和符号的数量。
反复利用
[sum_{i=m}^ninom{i}{m}=inom{n+1}{m+1} ]
[ans=sum_{i=1}^{n+1}sum_{k=0}^{i-1}a_{i-k}sum_{j=k}^{i-1}inom{j}{k}\
=sum_{i=1}^{n+1}sum_{k=1}^ia_ksum_{j=i-k}^{i-1}inom{j}{k}\
=sum_{i=1}^{n+1}sum_{k=1}^ia_ksum_{j=1}^kinom{i-j}{i-k}\
=sum_{k=1}^{n+1}a_ksum_{i=k}^{n+1}sum_{j=1}^kinom{i-j}{i-k}\
=sum_{k=1}^{n+1}a_ksum_{j=1}^ksum_{i=0}^{n+1-k}inom{i+k-j}{i}=sum_{k=1}^{n+1}a_ksum_{j=1}^ksum_{i=0}^{n+1-k}inom{i+k-j}{k-j}\
=sum_{k=1}^{n+1}a_ksum_{j=1}^kinom{n-j+2}{k-j+1}=sum_{k=1}^{n+1}a_ksum_{j=1}^kinom{n-j+2}{n-k+1}\
=sum_{k=1}^{n+1}a_ksum_{j=n-k+2}^{n+1}inom{j}{n-k+1}\
=sum_{k=1}^{n+1}a_kleft(inom{n+2}{n-k+2}-1
ight)
]
维护系数的前缀和即可。时间复杂度 (O(n+m))。
CO int N=6e5+10;
int fac[N],ifac[N];
int a[N],pool[N],*s=pool+1;
IN int binom(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
int n=read<int>(),m=read<int>();
fac[0]=1;
for(int i=1;i<=n+2;++i) fac[i]=mul(fac[i-1],i);
ifac[n+2]=fpow(fac[n+2],mod-2);
for(int i=n+1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
for(int i=1;i<=n+1;++i)if(read(a[i])<0) a[i]+=mod;
int ans=0;
s[0]=binom(n+2,1)-1;
ans=mul(a[n+1],s[0]);
for(int i=1;i<=n;++i){
s[i]=add(s[i-1],binom(n+2,n-i+2)-1);
ans=add(ans,mul(a[i],binom(n+2,n-i+2)-1));
}
printf("%d
",ans);
while(m--){
int l=read<int>(),r=read<int>(),p=read<int>();
if(p<0) p+=mod;
ans=add(ans,mul(add(s[r],mod-s[l-1]),p));
printf("%d
",ans);
}
return 0;
}