题目
原题链接
问题描述
思路
差分数组的优点在于牵一发而动全身,通过处理一个位置便可以将后续位置的值都改变。
我们此时面临的操作是对区间处理,而且处理不是简单的加上某个值,而是对位于
[
l
,
r
]
[l,r]
[l,r]中的
a
[
i
]
a[i]
a[i]加上
f
(
i
)
f(i)
f(i),
f
(
i
)
f(i)
f(i)是一个最高阶数不超过
5
5
5的多项式。
1.引入
在题目小W的糖果中,需要处理平方差分数组,也就是对于位置
l
l
l以及其右侧的每个位置需要加上
i
2
i^2
i2,其实这也是一个特殊的多项式,我们通过进行
3
3
3次差分:
[
1
,
4
,
9
,
16
,
25
]
?
[
1
,
3
,
5
,
7
,
9
]
?
[
1
,
2
,
2
,
2
,
2
]
?
[
1
,
1
,
0
,
0
,
0
]
[1,4,9,16,25]\Longrightarrow[1,3,5,7,9]\Longrightarrow[1,2,2,2,2]\Longrightarrow[1,1,0,0,0]
[1,4,9,16,25]?[1,3,5,7,9]?[1,2,2,2,2]?[1,1,0,0,0]
在数学上,有一个结论:最高次项为
n
n
n次的
n
n
n阶多项式做
n
+
1
n+1
n+1阶差分后余项为常数(非0项有限)。
依照这个定理,我们对一个序列上特定的位置加上特定的常数,再经过
n
+
1
n+1
n+1次前缀和操作,就可以对位于
[
l
,
+
∞
)
[l,+\infty)
[l,+∞)中的
a
[
i
]
a[i]
a[i]加上最高次项为
n
n
n次的
n
n
n阶多项式
f
(
i
)
f(i)
f(i)。
值得注意的是,如果我们对最高次项为
n
n
n次的
n
n
n阶多项式做
n
+
2
n+2
n+2阶差分,我们会得到什么样的结果呢? 依然使用上面的例子,再进行一次差分,我们将会得到序列
[
1
,
0
,
?
1
,
0
,
0
]
[1,0,-1,0,0]
[1,0,?1,0,0],这个序列依然是一个非
0
0
0项有限的序列。
此时又有了另一个问题,也就是这个非
0
0
0项有限的序列的长度可能会在什么范围内,我们取
f
(
x
)
=
x
5
+
x
4
+
x
3
+
x
2
+
x
+
6
f(x)=x^5+x^4+x^3+x^2+x+6
f(x)=x5+x4+x3+x2+x+6来看看
6
6
6次差分后也就
6
6
6项,所以我们一开始设定
10
10
10位就可以推出这个序列了。
2.分析
但上述题目中的操作并不是对右侧全部元素进行操作,而是对区间
[
l
,
r
]
[l,r]
[l,r]内部元素进行操作,所以我们需要对
[
r
+
1
,
+
∞
)
[r+1,+\infty)
[r+1,+∞)中的每个元素进行修正,此时也就是对这一段的每个元素加上
?
f
(
i
)
-f(i)
?f(i),依然可以将
?
f
(
i
)
-f(i)
?f(i)视作是一个多项式,经过多次差分得到一个非
0
0
0项有限的序列。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod =1e9+7;
const int N =1e5+7;
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
#define rif(i, a, b) for (int i = (a); i >= (b); i--)
ll t,n,m,q,a[N],l,r,k,c[15],p[2][15];
ll f(ll x, ll a[],ll k){
ll res = 0;
ll base = 1;
fir(i,0,k){
(res+=base*c[i])%=mod;
(base*=x)%=mod;
}
return res;
}
ll g(ll x,ll a[],ll k,ll l,ll r){
return (mod-f(x+r-l+1,a,k))%mod;
}
void P(ll a[], int len, int cnt){
while(cnt--){
fir(i,1,len){
(a[i]+=a[i-1])%=mod;
}
}
}
void D(ll a[], int len, int cnt){
while(cnt--){
rif(i,len,0){
a[i]=(a[i]-a[i-1]+mod)%mod;
}
}
}
int main(){
scanf("%lld %lld %lld", &n, &m, &q);
fir(i,1,n)scanf("%lld", &a[i]);
D(a,n,6);
while(m--){
cin>>l>>r>>k;
rif(i,k,0)scanf("%lld", &c[i]);
fir(i,1,10){
p[0][i]=f(i,c,k);
p[1][i]=g(i,c,k,l,r);
}
D(p[0],10,6);
D(p[1],10,6);
fir(i,1,10){
(a[l+i-1]+=p[0][i])%=mod;
(a[r+i]+=p[1][i])%=mod;
}
}
P(a,n,7);
while(q--){
scanf("%lld %lld", &l, &r);
printf("%lld\n",((a[r]-a[l-1])%mod+mod)%mod);
}
}
|