D - Between Two Arrays
思路:
首先考虑暴力
d
p
dp
dp
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示长度为
i
i
i 的序列
c
c
c ,
c
i
c_i
ci 为
j
j
j 时的合法序列数
f
[
i
]
[
j
]
=
∑
a
i
−
1
m
i
n
(
j
,
b
i
−
1
)
f
[
i
−
1
]
[
k
]
,
j
∈
[
a
i
,
b
i
]
f[i][j]=\sum_{a_{i-1}}^{min(j,b_{i-1})}f[i-1][k], \ j\in[a_i,b_i]
f[i][j]=∑ai−1min(j,bi−1)f[i−1][k], j∈[ai,bi]
初始化
f
[
0
]
[
i
]
=
1
,
i
∈
[
0
,
3000
]
f[0][i]=1, \ i\in[0,3000]
f[0][i]=1, i∈[0,3000]
可以发现求和式可以用前缀和优化
设当前位置为
i
i
i
维护
s
u
m
[
j
]
=
∑
k
=
0
j
f
[
i
−
1
]
[
k
]
,
i
∈
[
1
,
n
]
sum[j]=\sum_{k=0}^{j}f[i-1][k], \ i\in[1,n]
sum[j]=∑k=0jf[i−1][k], i∈[1,n]
那么转移方程优化为
O
(
1
)
O(1)
O(1)
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int a[maxn], b[maxn];
int f[3009][3009];
// f[i][j] 表示长度为i的序列c,c_i为j时的合法序列数
int sum[3009];// 维护上一个序列的前缀和
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> a[i];
}
for(int i = 1; i <= n; ++i) {
cin >> b[i];
}
// for(int i = 0; i <= 3000; ++i) f[0][i] = 1;
sum[0] = 1;
for(int i = 1; i <= 3000; ++i) sum[i] = sum[i-1] + f[0][i];
for(int i = 1; i <= n; ++i) {
for(int j = a[i]; j <= b[i]; ++j) {
// for(int k = a[i-1]; k <= min(j, b[i-1]); ++k) {
// f[i][j] += f[i-1][k];
// f[i][j] %= mod;
// }
int r = min(j, b[i-1]), l = a[i-1] - 1;
f[i][j] += sum[r];
if(l >= 0) f[i][j] -= sum[l];
(f[i][j] += mod) %= mod;
}
for(int j = 0; j <= 3000; ++j) {
sum[j] = f[i][j];
if(j > 0) (sum[j] += sum[j-1]) %= mod;
}
}
int ans = sum[b[n]];
if(a[n] - 1 >= 0) ans -= sum[a[n] - 1];
(ans += mod) %= mod;
cout << ans;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}