宝宝龙好强,拜谢宝宝龙
ridewindHE
·
·
题解
同机房大佬宝宝龙出的题,上午模拟赛被宝宝龙大佬拉爆了,写个题解膜拜一下他。
题意
## 思路
如果维护 $n$ 个数组时间复杂度是 $O(n^2 (p+q))$,显然会超时。
所以我们考虑维护 $a_{0}$,查询时求出 $a_{x,j}$ 包含多少个 $a_{0}$ 项,展开前缀和得:
$$
a_{x,j}=\sum_{i=1}^{j} a_{0,i}\times C_{j-i+x-1}^{x-1}
$$
那么:
$$
\sum_{j=l}^{r} a_{x,j}=\sum_{i=1}^{r}a_{0,i} \sum_{d=\max(l-i,0)}^{r-i}C_{d+x-1}^{x-1}
$$
然后利用插板法可得:
$$
\sum_{d=0}^{m}C_{d+x-1}^{x-1}=C_{m+x}^{x}
$$
所以内层求和可以 $O(1)$ 计算:
$$
\sum_{d=\max(l-i,0)}^{r-i}C_{d+x-1}^{x-1}=C_{x+r-i,x}-C_{x+\max(l-i,0)-1,x}
$$
因此查询操作已经解决,接下来,我们考虑区间加操作。
我们需要考虑 $a_{0}$ 要怎么改,才能让 $a_{x}$ 的 $[l,r]$ 项每项都加上 $k$。
首先 $a_{i}$ 是 $a_{i-1}$ 的前缀和数组,那么 $a_{i-1}$ 就是 $a_{i}$ 的差分数组。所以我们可以从 $a_{x}$ 出发,一层一层向下差分。
假设 $a_{x}$ 的 $[l,r]$ 项都加上了 $k$,那么 $a_{x-1}$ 的 $l$ 处 $+k$,$r+1$ 处 $-k$。
然后再从 $a_{x-1}$ 推到 $a_{x-2}$,那么 $a_{x-2}$ 的 $l$ 处 $+k$,$l+1$ 处 $-k$,$r+1$ 处 $-k$,$r+2$ 处 $+k$。
接着再从 $a_{x-2}$ 推到 $a_{x-3}$,那么 $a_{x-3}$ 的 $l$ 处 $+k$,$l+1$ 处 $-2\times k$,$l+2$ 处 $+k$,$r+1$ 处 $-k$,$r+2$ 处 $+2\times k$,$r+3$ 处 $-k$。
以此类推。
经过几次推导,我们可以得出结论,这个修改的数的符号由差分展开时的偏移量 $i$ 的奇偶性决定,系数很像一个杨辉三角,直接用组合数求即可。
时间复杂度 $O(n(p+q))$。
注意,修改时 $x=0$ 需要单独处理,$a_{0,i}$ 和 $k$ 可能为负数,要注意。
## 代码
:::success[AC code]
```cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p=1e9+7;
ll qp(ll a,ll b){
a%=p;
ll res=1;
while(b){
if(b&1)res=res*a%p;
a=a*a%p,b>>=1;
}
return res;
}
ll fac[610],inv[610];
void init(int n){
fac[0]=inv[0]=1;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%p;
inv[n]=qp(fac[n],p-2);
for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%p;
}
ll C(int x,int y){
if(y>x||y<0)return 0;
return fac[x]*inv[x-y]%p*inv[y]%p;
}
int a[310];
int main(){
int n,q1,q2;
cin>>n>>q1>>q2;
int q=q1+q2;
init(n*2);
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]=(a[i]%p+p)%p;
}
while(q--){
int op,x,l,r,k;
cin>>op>>x>>l>>r;
if(op==1){
cin>>k;
k=(k%p+p)%p;
if(!x){
for(int i=l;i<=r;i++)a[i]=(a[i]+k)%p;
continue;
}
for(int i=0;i<x&&l+i<=n;i++){
if(i&1)a[l+i]=((a[l+i]-k*C(x-1,i)%p)%p+p)%p;
else a[l+i]=(a[l+i]+k*C(x-1,i)%p)%p;
}
for(int i=0;i<x&&r+1+i<=n;i++){
if(i&1)a[r+1+i]=(a[r+1+i]+k*C(x-1,i)%p)%p;
else a[r+1+i]=((a[r+1+i]-k*C(x-1,i)%p)%p+p)%p;
}
}else{
int ans=0;
for(int i=1;i<=r;i++)ans=(ans+a[i]*((C(x+r-i,x)-C(x+max(l-i,0)-1,x))%p+p)%p)%p;
cout<<ans<<"\n";
}
}
return 0;
}
```
:::