题目
思路
说个笑话:我一上来就是 传递糖果,于是一个人可以传递 ∑ a \sum a ∑a 个糖果……
事实上普通
d
p
\tt dp
dp 应该很简单。设
d
p
i
,
j
dp_{i,j}
dpi,j 为第
i
i
i 个人给出
j
j
j 个糖果,有转移
d
p
i
,
j
=
∑
k
⩽
a
i
−
1
(
a
i
+
k
−
j
)
⋅
d
p
i
−
1
,
k
dp_{i,j}=\sum_{k\leqslant a_{i-1}}(a_i+k-j)\cdot dp_{i-1,k}
dpi,j=k⩽ai−1∑(ai+k−j)⋅dpi−1,k
由于
j
,
k
j,k
j,k 实际上是独立的,我们很有可能直接从
∑
k
⩽
a
i
−
1
d
p
i
−
1
,
k
\sum_{k\leqslant a_{i-1}}dp_{i-1,k}
∑k⩽ai−1dpi−1,k 和
∑
k
⩽
a
i
−
1
d
p
i
−
1
,
k
⋅
k
\sum_{k\leqslant a_{i-1}}dp_{i-1,k}\cdot k
∑k⩽ai−1dpi−1,k⋅k 得到
∑
j
⩽
a
i
d
p
i
,
j
\sum_{j\leqslant a_i}dp_{i,j}
∑j⩽aidpi,j 。
∑
j
⩽
a
i
d
p
i
,
j
=
s
[
0
]
(
a
i
)
∑
k
⩽
a
i
−
1
(
a
i
+
k
)
⋅
d
p
i
−
1
,
k
−
s
[
1
]
(
a
i
)
∑
k
⩽
a
i
−
1
d
p
i
−
1
,
k
∑
j
⩽
a
i
d
p
i
,
j
⋅
j
=
s
[
1
]
(
a
i
)
∑
k
⩽
a
i
−
1
(
a
i
+
k
)
⋅
d
p
i
−
1
,
k
−
s
[
2
]
(
a
i
)
∑
k
⩽
a
i
−
1
d
p
i
−
1
,
k
\sum_{j\leqslant a_i}dp_{i,j}=s^{[0]}(a_i)\sum_{k\leqslant a_{i-1}}(a_i+k)\cdot dp_{i-1,k}-s^{[1]}(a_i)\sum_{k\leqslant a_{i-1}}dp_{i-1,k}\\ \sum_{j\leqslant a_i}dp_{i,j}\cdot j=s^{[1]}(a_i)\sum_{k\leqslant a_{i-1}}(a_i+k)\cdot dp_{i-1,k}-s^{[2]}(a_i)\sum_{k\leqslant a_{i-1}}dp_{i-1,k}
j⩽ai∑dpi,j=s[0](ai)k⩽ai−1∑(ai+k)⋅dpi−1,k−s[1](ai)k⩽ai−1∑dpi−1,kj⩽ai∑dpi,j⋅j=s[1](ai)k⩽ai−1∑(ai+k)⋅dpi−1,k−s[2](ai)k⩽ai−1∑dpi−1,k
其中 s [ p ] ( v ) = ∑ i = 0 v i p s^{[p]}(v)=\sum_{i=0}^{v}i^p s[p](v)=∑i=0vip 。这很容易理解。
但是这个会算重,因为不同的给出量不代表不同的剩余量。事实上,决定剩余量的是差分值,所以我们强迫一个值为 0 0 0 即可。枚举它,时间复杂度 O ( n 2 ) \mathcal O(n^2) O(n2) 。
然而这是线性变化,可以写出转移矩阵
[
s
[
0
]
⋅
a
i
−
s
[
1
]
s
[
1
]
⋅
a
i
−
s
[
2
]
s
[
0
]
s
[
1
]
]
\begin{bmatrix} s^{[0]}\cdot a_i-s^{[1]} & s^{[1]}\cdot a_i-s^{[2]} \\ s^{[0]} & s^{[1]} \end{bmatrix}
[s[0]⋅ai−s[1]s[0]s[1]⋅ai−s[2]s[1]]
注:状态矩阵是行向量。那么维护矩阵的前后缀乘积即可 O ( 1 ) \mathcal O(1) O(1) 计算。总复杂度 O ( n ) \mathcal O(n) O(n) 。
代码
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long int_;
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; '0'>c||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
void writeUnsigned(const unsigned &x){
if(x > 9) writeUnsigned(x/10);
putchar((x-x/10*10)^48);
}
inline void writeint(const int &x){
if(x < 0){
putchar('-');
writeUnsigned(-x);
}
else writeUnsigned(x);
}
const int Mod = 998244353;
const int inv3 = (Mod+1)/3;
struct Matrix{
int a[2][2];
void clear(){ memset(a,0,2*2<<2); }
Matrix operator * (const Matrix &b) const {
Matrix c; c.clear();
rep(i,0,1) rep(j,0,1) rep(k,0,1)
c.a[i][k] = static_cast<int>(
(c.a[i][k]+int_(a[i][j])*b.a[j][k])%Mod);
return c;
}
static Matrix I(){
Matrix c;
c.a[0][1] = c.a[1][0] = 0;
c.a[0][0] = c.a[1][1] = 1;
return c;
}
};
const int MAXN = 1000005;
/// @param f if x can be 0
Matrix fuck(int x,bool f=true){
Matrix res;
int &s0 = res.a[1][0] = x+f;
int &s1 = res.a[1][1] = int((int_(x+1)*x>>1)%Mod);
int s2 = int(s1*int_(x<<1|1)%Mod*inv3%Mod);
res.a[0][0] = int((int_(s0)*x+Mod-s1)%Mod);
res.a[0][1] = int((int_(s1)*x+Mod-s2)%Mod);
return res;
}
Matrix pre[MAXN], suf[MAXN];
int a[MAXN];
int main(){
int n = readint(), ans = 0;
pre[0] = suf[n+1] = Matrix::I();
rep(i,1,n){
a[i] = readint();
pre[i] = pre[i-1]*fuck(a[i],false);
}
drep(i,n,1){
suf[i] = fuck(a[i],true)*suf[i+1];
Matrix mat; mat.clear();
mat.a[0][0] = 1; // f(i,0) = 1
mat = mat*suf[i+1]*pre[i-1];
ans = int((ans+int_(a[i])*mat.a[0][0])%Mod);
ans = (ans+mat.a[0][1])%Mod;
}
printf("%d\n",ans);
return 0;
}