給定長度 ≤ 10⁵ 的數字字符串,求所有不重複非空子序列代表的數值之和,模 1,000,000,007。子序列不允許前導零(除非子序列本身是 "0")。
dp[d]:以數字 d (0..9) 結尾的所有合法子序列的數值和。cnt[d]:以 d 結尾的合法子序列個數。
遍歷字符串每個字符 x:
newSum = (Σ dp[d]) * 10 + (Σ cnt[d] + (x>0?1:0)) * x。newCnt = Σ cnt[d] + (x>0?1:0)。dp[x] = newSum, cnt[x] = newCnt(覆蓋,因同尾數字只保留最新狀態,自動去重)。import java.util.*;
public class Main {
static final int MOD = 1000000007;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int T = in.nextInt();
while (T-- > 0) {
String s = in.next();
long[] dp = new long[10], cnt = new long[10];
for (char ch : s.toCharArray()) {
int x = ch - '0';
long sum = 0, c = 0;
for (int d = 0; d < 10; ++d) {
sum = (sum + dp[d]) % MOD;
c = (c + cnt[d]) % MOD;
}
if (x > 0) c = (c + 1) % MOD;
dp[x] = (sum * 10 + c * x) % MOD;
cnt[x] = c;
}
long ans = 0;
for (int d = 0; d < 10; ++d) ans = (ans + dp[d]) % MOD;
System.out.println(ans);
}
}
}
c+1),但可附加在現有子序列後。sum*10 + cnt*x。CSU 1354 是「子序列計數去重 + 數值和」的精妙 DP。核心技巧:按尾數字分組狀態 + 覆蓋更新實現去重 + 線性遞推公式。同類思想適用於「不同子序列個數」、「子序列和」等變體問題。