题面:给定长度为n的两升序数组A[i]和B[i],其中A[i]<=A[i+1],B[i]<=B[i+1],并且0<=A[i]<=B[i]<=3000,找长度为n的数组C[i],满足A[i]<=C[i]<=B[i]。求满足该条件C的个数,结果对998244353取余。
范围:1 <= n <= 3000
分析:设dp[i][j]表示前i个数以j结尾的方案数,那么dp[i][j]=sum(dp[i-1][k]), 0<=k<j,这样递推时间复杂度是O(n^3),会TLE。观察发现这个可以用前缀和优化到O(n^2),另外可以用滚动数组优化空间到O(n)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=b;i>=a;i--)
// mint模板略
const int N = 3000;
int n, A[N+1], B[N+1];
mint dp[N+1], pre[N+1];
mint sum(int l, int r) {
return l ? pre[r] - pre[l-1] : pre[r];
}
void solve() {
cin >> n;
rep(i,1,n) cin >> A[i];
rep(i,1,n) cin >> B[i];
dp[0] = 1;
partial_sum(dp, dp+N+1, pre);
rep(i,1,n) {
rep(j,0,N) dp[j] = 0;
rep(j,A[i],B[i]) {
dp[j] = sum(A[i-1], j);
}
partial_sum(dp, dp+N+1, pre);
}
cout << pre[N] << "\n";
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--) solve();
return 0;
}
标签:前缀和 线性dp