题意:给定一个长度为n的正整数数组 a i a_i ai,求有多少数组 b i b_i bi,满足 1 < = b i < = a i , b i ! = b i + 1 1<=b_i<=a_i,b_i!=b_{i+1} 1<=bi<=ai,bi!=bi+1。 1 < = n < = 2 e 5 , 1 < = a i < = 2 e 9 1<=n<=2e5,1<=a_i<=2e9 1<=n<=2e5,1<=ai<=2e9
另一种思路
思路:
对于长度为
n
n
n的数组,如果它有
k
k
k对
b
i
=
=
b
i
+
1
b_i==b_{i+1}
bi==bi+1的元素,那么相应的,它有
n
−
1
−
k
n-1-k
n−1−k对
b
i
!
=
b
i
+
1
b_i!=b_{i+1}
bi!=bi+1的位置,它相当于被切割成
n
−
k
n-k
n−k段,段内元素相等。
令 f [ i ] [ x ] f[i][x] f[i][x]表示取前i个元素,且被分割为 x x x段的b数组个数。则 f [ i ] [ x ] = f [ p o s ] [ x ] + ∑ j = p o s i − 1 f [ j ] [ x − 1 ] ∗ a [ i ] f[i][x]=f[pos][x]+\sum_{j=pos}^{i-1}f[j][x-1]*a[i] f[i][x]=f[pos][x]+∑j=posi−1f[j][x−1]∗a[i],其中 p o s pos pos表示前 i − 1 i-1 i−1个元素中,从右到左,第一个小于 a i a_i ai的元素的下标(可以用单调栈来维护)。此转移方程很好理解,第一部分 f [ p o s ] [ x ] f[pos][x] f[pos][x]表示 b p o s + 1 , b p o s + 2 , . . . , b i b_{pos+1},b_{pos+2},...,b_i bpos+1,bpos+2,...,bi取和 b p o s b_{pos} bpos相同的值,此时段数不变;第二部分表示 b j + 1 , . . . , b i − 1 b_{j+1},...,b_{i-1} bj+1,...,bi−1取和 b i b_i bi相同的值,此时新增了一段连续相同的值(与 b j b_j bj不同)。
但我们发现,
f
[
i
]
[
x
]
f[i][x]
f[i][x]在计算过程中,也包含了
f
[
i
]
[
x
−
1
]
f[i][x-1]
f[i][x−1]。我们在计算
∑
j
=
p
o
s
i
−
1
f
[
j
]
[
x
−
1
]
∗
a
[
i
]
\sum_{j=pos}^{i-1}f[j][x-1]*a[i]
∑j=posi−1f[j][x−1]∗a[i]时,实际上也算进了
b
i
=
=
b
j
b_i==b_j
bi==bj的场景。因此,我们需要减去
f
[
i
]
[
x
−
1
]
f[i][x-1]
f[i][x−1]。所以,有
r
e
a
l
_
f
[
n
]
[
n
]
=
f
[
n
]
[
n
]
−
r
e
a
l
_
f
[
n
]
[
n
−
1
]
real\_f[n][n]=f[n][n]-real\_f[n][n-1]
real_f[n][n]=f[n][n]−real_f[n][n−1]
r
e
a
l
_
f
[
n
]
[
n
−
1
]
=
f
[
n
]
[
n
−
1
]
−
r
e
a
l
_
f
[
n
]
[
n
−
2
]
real\_f[n][n-1]=f[n][n-1]-real\_f[n][n-2]
real_f[n][n−1]=f[n][n−1]−real_f[n][n−2]
…
r
e
a
l
_
f
[
n
]
[
1
]
=
f
[
n
]
[
1
]
−
r
e
a
l
_
f
[
n
]
[
0
]
real\_f[n][1]=f[n][1]-real\_f[n][0]
real_f[n][1]=f[n][1]−real_f[n][0]
r
e
a
l
_
f
[
n
]
[
0
]
=
f
[
n
]
[
0
]
real\_f[n][0]=f[n][0]
real_f[n][0]=f[n][0]
这是一个容斥过程
r
e
a
l
_
f
[
n
]
[
n
]
=
f
[
n
]
[
n
]
−
f
[
n
]
[
n
−
1
]
+
f
[
n
]
[
n
−
2
]
−
.
.
.
real\_f[n][n]=f[n][n]-f[n][n-1]+f[n][n-2]-...
real_f[n][n]=f[n][n]−f[n][n−1]+f[n][n−2]−...
我们可以发现, f [ n ] [ x ] f[n][x] f[n][x]的x,如果x和n奇偶性相同,则为正贡献;否则为负贡献。
重新定义
f
[
i
]
[
x
]
f[i][x]
f[i][x],取前i个数,且段数个数为奇数(x=1)或偶数(x=0)的个数。
则答案为
f
[
n
]
[
0
]
−
f
[
n
]
[
1
]
f[n][0]-f[n][1]
f[n][0]−f[n][1](n为偶数)或
f
[
n
]
[
1
]
−
f
[
n
]
[
0
]
f[n][1]-f[n][0]
f[n][1]−f[n][0](n为奇数)。
贴上zltzlt大佬的代码
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 200100;
const ll mod = 998244353;
ll n, a[maxn], st[maxn], top;
ll f[maxn][2], g[maxn][2];
void solve() {
scanf("%lld", &n);
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
f[0][0] = g[0][0] = 1;
for (int i = 1; i <= n; ++i) {
while (top && a[i] <= a[st[top]]) {
--top;
}
if (top) {
f[i][0] = (f[st[top]][0] + (g[i - 1][1] - g[st[top] - 1][1] + mod) * a[i]) % mod;
f[i][1] = (f[st[top]][1] + (g[i - 1][0] - g[st[top] - 1][0] + mod) * a[i]) % mod;
} else {
f[i][0] = g[i - 1][1] * a[i] % mod;
f[i][1] = g[i - 1][0] * a[i] % mod;
}
g[i][0] = (g[i - 1][0] + f[i][0]) % mod;
g[i][1] = (g[i - 1][1] + f[i][1]) % mod;
st[++top] = i;
}
printf("%lld", (n & 1) ? (f[n][1] - f[n][0] + mod) % mod : (f[n][0] - f[n][1] + mod) % mod);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
//By zltzlt,
// http://codeforces.com/profile/zltzlt