1. 程式人生 > 其它 >ABC222 D - Between Two Arrays(dp)

ABC222 D - Between Two Arrays(dp)

目錄

Description

有兩個不降陣列,其中 \(a_i<=b_i\), 求有多少個不降陣列 \(c\) 滿足 \(a_i<=c_i<=b_i\)

State

\(1<=n<=3000\)

\(0<=a_i<=b_i<=3000\)

Input

2
1 1
2 3

Output

5

Solution

由題意可以寫出方程 \(dp[i][j]=dp[i-1][1...j]\) 表示到 \(i\) 位置以 \(j\) 結尾的陣列有多少個

但是這樣轉移時間上為 \(O(nB^2) \ B\)\(b\) 陣列的值域

但是這種轉移是類似字首和的形式,所以可以利用一個字首和陣列 \(sum[j]\) 優化掉一維 \(B\)

這樣空間上也可以優化至一維,\(dp\) 方程變得與 \(i\) 無關


Code

const int N = 3e3 + 5;
 
    int n, m, k, _;
    int a[N];
    int b[N];
    ll dp[N];
    ll sum[N];

ll adp(ll &x)
{
    x %= mod;
    x += mod;
    x %= mod;
    return x;
}

signed main()
{
    // IOS;
    while(~ sd(n)){
        rep(i, 1, n) sd(a[i]);
        rep(i, 1, n) sd(b[i]);
        for(int j = a[1]; j <= b[1]; j ++){
            dp[j] = 1;
            sum[j] = sum[j - 1] + dp[j];
        }
        for(int i = b[1] + 1; i <= b[2]; i ++){
            sum[i] = sum[i - 1];
        }
        for(int i = 2; i <= n; i ++){
            for(int j = a[i]; j <= b[i]; j ++){
                dp[j] = sum[j];
                adp(dp[j]);
            }
            sum[a[i] - 1] = 0;
            for(int j = a[i]; j <= b[i]; j ++){
                sum[j] = sum[j - 1] + dp[j];
                adp(sum[j]);
            }
            for(int j = b[i] + 1; j <= b[i + 1]; j ++){
                sum[j] = sum[j - 1];
            }
        }
        pll(sum[b[n]]);
    }
    // PAUSE;
    return 0;
}