[題解]AT_abc288_f [ABC288F] Integer Division

WaterSunHB發表於2024-06-23

思路

定義 \(dp_i\) 表示前 \(i\) 位所能得到的答案。

那麼,不難得出狀態轉移方程,其中 \(X_{i,j}\) 表示 \(X_{i,j}\) 轉為的數字:

\[ dp_i = \sum_{j = 1}^{i - 1}(dp_j \times X_{j + 1 \sim i}) + X_{1,i} \]

這樣的時間複雜度為 \(\Theta(n^2)\) 過不了,考慮用字首和最佳化。

\[ \begin{aligned} dp_i =& \sum_{j = 1}^{i - 1}(dp_j \times X_{j + 1,i}) + X_{1,i}\\ =& \sum_{j = 1}^{i - 1}(dp_j \times (10 \times X_{j + 1,i - 1} + X_{i,i})) + X_{1,i}\\ =& 10 \times dp_{i - 1} + X_{i,i} \times \sum_{j = 1}^{i - 1}(dp_j) + X_{1,i} \end{aligned} \]

然後用字首和維護一下 \(\sum_{j = 1}^{i - 1}(dp_j)\) 即可。

時間複雜度 \(\Theta(n)\)

注意:為了程式碼簡介,我們規定 \(dp_0 = sum_0 = 1\),這樣就可以省去 \(X_{1,i}\)。因為每一次 \(sum_i\) 都會多 \(1\),加起來就正好為 \(X_{1,n}\)

Code

#include <bits/stdc++.h>  
#define int long long  
#define re register  
  
using namespace std;  
  
const int N = 2e5 + 10,mod = 998244353;  
int n;  
int dp[N],sum[N];  
string s;  
  
signed main(){  
    ios::sync_with_stdio(0);  
    cin.tie(0);  
    cout.tie(0);  
    cin >> n >> s;  
    s = ' ' + s;  
    dp[1] = s[1] - '0';  
    sum[1] = dp[1] + 1;  
    for (re int i = 2;i <= n;i++){  
        dp[i] = (10 * dp[i - 1] + (s[i] - '0') * sum[i - 1]) % mod;  
        sum[i] = (sum[i - 1] + dp[i]) % mod;  
    }  
    printf("%lld",dp[n]);  
    return 0;  
}  

相關文章