[ARC052D] 9

题意翻译是假的,骗了我十分钟(恼)。

题目大意

给定两个正整数 \(k\)\(m\),需要求出有多少个正整数 \(n\) 满足 \(1 \leq n \leq m\)\(n \equiv S_n(\operatorname{mod} k)\)

\(1 \leq m \leq 10^{10}\)

思路

范围 \(10^{10}\),考虑根号复杂度。

考虑根号分治,设 \(T\)\(\sqrt{m}\) 级别。

  • \(K \geq T\)

容易发现,\(S_n\) 的值很小,最大也不会超过 \(90\)

那我们可以枚举数字和 \(S_n\)

那么与 \(S_n\) 关于 \(k\) 同余的 \(n\) 的个数不会超过 \(\left\lfloor \frac{m}{k} \right\rfloor + 1\) 个。

直接枚举这些 \(n\) 就可以了,复杂度达标。

  • \(K < T\)

考虑把 \(n \operatorname{mod} k\) 的值作为一维放状态里,直接数位 DP 即可。

Code

// ARC052D
#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 10500;

int n,m,k;

int dp[15][N][95][2];
// dp[i][j][k][l] : 
// 第 i 位,Sn % k = j,Sn = k,是否为上界 

int num[15],tot;

int dfs(int cnt,int mod,int sum,int lim) {
    if(cnt == 0) {
        if(mod == sum % k && sum != 0)
            return 1;
        
        return 0;
    }

    if(dp[cnt][mod][sum][lim] != -1) 
        return dp[cnt][mod][sum][lim];

    int Max = 9,ans = 0;

    if(lim)
        Max = num[cnt];
    
    for(int i = 0;i <= Max; i++)
        ans += dfs(cnt - 1,(mod * 10 + i) % k,sum + i,lim && i == Max);

    return dp[cnt][mod][sum][lim] = ans;
}

int Work(int x) {
    while(x) {
        tot ++;
        num[tot] = x % 10;
        x /= 10;
    }

    return dfs(tot,0,0,1);
}

signed main() {
    cin >> k >> m;

    memset(dp,255,sizeof(dp));

    if(k <= 1e4) 
        cout << Work(m) << "\n";
    else {
        int ans = 0;

        for(int i = 0;i <= 90; i++) {
            for(int j = i;j <= m; j += k) {
                int x = j,Sn = 0;

                while(x) {
                    Sn += x % 10;
                    x /= 10;
                }

                if(Sn % k == i)
                    ans ++;
            }
        }

        cout << ans - 1 << "\n";
        // 去掉 0 
    }
    return 0;
}
posted @ 2023-09-18 21:43  -白简-  阅读(21)  评论(0编辑  收藏  举报