公式
E - 数字の揺れ値 / Fluctuation Value of Digits 解説
by
E - 数字の揺れ値 / Fluctuation Value of Digits 解説
by
kyopro_friends
この問題は桁DPにより解くことができます。
下の桁から決めていく桁DPを考えます。
\(\mathrm{dp}_X[i][\mathrm{leq}][\mathrm{pre}][k]\) を、以下の条件を全て満たす長さ \(i\) の数字列 \(S\) の個数とします。
- \(S\) を整数と解釈したとき、\(X \bmod 10^i\) 以下なら \(\mathrm{leq}\) は True、そうでないなら False である
- \(S\) の先頭の文字は \(\mathrm{pre}\) である
- \(S\) の leading zero を含めた揺れ値は \(k\) である
求める答えは、\(N\) の桁数を \(n\) として
\(\sum\mathrm{dp}_N[< n][*][\neq 0][K]+\sum \mathrm{dp}_N[n][\mathrm{True}][\neq 0][K]\)
となります。DPの遷移は、\(S\) の先頭に追加する文字の種類を全て試せばよいです。
基数を \(B\) として、計算量は \(O(KB^2 \log_B N)\) になります。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n, k;
cin >> n >> k;
vector<int>nn;
while(n){
nn.push_back(n%10);
n /= 10;
}
map<array<int,3>, long long> dp;
for(int d=0; d<10; d++){
dp[{d<=nn[0], d, 0}] = 1;
}
long long ans = 0;
for(int i=1; i<nn.size(); i++){
int c = nn[i];
map<array<int,3>, long long> new_dp;
for(auto [key, val]: dp){
auto [leq, pre, s] = key;
if(s == k && pre != 0){
ans += val;
}
for(int d=0; d<10; d++){
array<int, 3> new_key = {d<c || (d==c && leq), d, s+abs(d-pre)};
new_dp[new_key] += val;
}
}
swap(dp, new_dp);
}
for(auto [key, val]: dp){
auto [leq, pre, s] = key;
if(s == k && pre != 0 && leq){
ans += val;
}
}
cout << ans << endl;
}
実装例 (Python)
from collections import defaultdict
N, K = input().split()
K = int(K)
dp = defaultdict(int)
for d in range(10):
dp[(d<=int(N[-1]), d, 0)] = 1
ans = 0
for i in range(len(N)-2, -1, -1):
c = int(N[i])
new_dp = defaultdict(int)
for (leq, pre, s), val in dp.items():
if s == K and pre != 0:
ans += val
for d in range(10):
new_key = (d<c or (d==c and leq), d, s+abs(d-pre))
new_dp[new_key] += val
dp = new_dp
for (leq, pre, s), val in dp.items():
if s == K and pre != 0 and leq:
ans += val
print(ans)
投稿日時:
最終更新:
