线性DPCF1513C Add One的代码不知道为什么错了

题目链接codeforces
题目链接洛谷

Add One

题面翻译

称“将一个数上每一位的值$+1$”为一次操作,例如对于$93$进行一次操作后的结果为$104$。输入$n,m$,输出对$n$进行$m$次操作的结果。

题目描述

You are given an integer $ n $ . You have to apply $ m $ operations to it.

In a single operation, you must replace every digit $ d $ of the number with the decimal representation of integer $ d + 1 $ . For example, $ 1912 $ becomes $ 21023 $ after applying the operation once.

You have to find the length of $ n $ after applying $ m $ operations. Since the answer can be very large, print it modulo $ 10^9+7 $ .

输入格式

The first line contains a single integer $ t $ ( $ 1 \le t \le 2 \cdot 10^5 $ ) — the number of test cases.

The only line of each test case contains two integers $ n $ ( $ 1 \le n \le 10^9 $ ) and $ m $ ( $ 1 \le m \le 2 \cdot 10^5 $ ) — the initial number and the number of operations.

输出格式

For each test case output the length of the resulting number modulo $ 10^9+7 $ .

样例 #1

样例输入 #1

5
1912 1
5 6
999 1
88 2
12 100

样例输出 #1

5
2
6
4
2115

提示

For the first test, $ 1912 $ becomes $ 21023 $ after $ 1 $ operation which is of length $ 5 $ .

For the second test, $ 5 $ becomes $ 21 $ after $ 6 $ operations which is of length $ 2 $ .

For the third test, $ 999 $ becomes $ 101010 $ after $ 1 $ operation which is of length $ 6 $ .

For the fourth test, $ 88 $ becomes $ 1010 $ after $ 2 $ operations which is of length $ 4 $ .

我的错误代码

#include 
#include 
#include 

using namespace std;

const int mod = 1e9 + 7;

inline int read() {
    int s = 0, w = 1;
    char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') w = -1; c = getchar();}
    while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
    return s * w;
}

int n, m;
long long a[10][200010];
// a[初始数字][扩展次数] = 扩展后的位数

int main() {    
    for (int i = 0; i <= 9; i ++) {
        a[i][0] = 1;
    }
    
    for (int i = 0; i <= 9; i ++) { // 初始数字
        for (int j = 1; j <= 200000; j ++) { // 扩展次数
            a[i][j] = a[i][j-1];
            if (j >= 11)
                a[i][j] = (a[i][j] + a[i][j-9] - a[i][j-10] + a[i][j-10] - a[i][j-11]) % mod;
            /*
              因为数字9可以由0和1增加得到
              所以:a[i][j-9] - a[i][j-10] + a[i][j-10] - a[i][j-11]
              表示数字i扩展j次后的数字中数字9的个数。
              其中a[i][j-9] - a[i][j-10]是数字i在扩展第j-9次后
              新出现的数字1的个数;
              其中a[i][j-10] - a[i][j-11]是数字i在扩展第j-10次后
              新出现的数字0的个数;
             */
            else if (j == 10 - i || i == 9 && j == 10)
                a[i][j] = (a[i][j] + 1) % mod;
        }
    }
    
    int t = read(); 
    while (t --) {
        n = read(); m = read();
        long long sum = 0;
        while (n) {
            sum = (sum + a[n%10][m]) % mod;
            n /= 10;
        }
        printf("%lld\n", sum);
    }
    
    return 0;
}

参考GPT和自己的思路:

下面是你的错误代码:

int n, m;
// 多组数据,数组开大点
long long a[10][200010];
// a[初始数字][扩展次数] = 扩展后的位数
// 数据可能比较大,取模

int main() {    
    // 预处理,初始化10之前的数,也就是0~9
    for (int i = 0; i <= 9; i ++) {
        a[i][0] = 1; // 对于0次扩展,自己不变
    }
    for (int i = 0; i <= 9; i ++) { // 初始数字
        for (int j = 1; j <= 200000; j ++) { // 扩展次数
            a[i][j] = a[i][j-1];
            if (j >= 11)
                // 对于当前位数j,统计的是自身i在j次扩展时的数字个数
                a[i][j] = (a[i][j] + a[i][j-9] - a[i][j-10] + a[i][j-10] - a[i][j-11]) % mod;
                /*
                因为数字9可以由0和1增加得到,假设我们从x扩展到y,
                那么y与x一定最多只多了一位,
                因此我们可以用a[i][j-9]来表示是在1后面加上i扩展了j-10位的
                数字前面在并上0或不变得到的,即a[i][j-9] - a[i][j-10]
                如果不加0而是加1的话,就变成了i+1的后9位,即a[i][j-10] - a[i][j-11]
                数字9会多算,所以减去前面的再加上后面的,就是实际得到的结果
                */
            else if (j == 10 - i)
                a[i][j] = (a[i][j] + 1) % mod;
                // 由于加1后每一位都变成了1,因为+1与之前不同,直接+1即可
        }
    }

    int t = read();
    while (t --) {
        n = read(); m = read();
        long long sum = 0;
        while (n) {
            // 从低位到高位记录总共的数字个数,取模
            sum = (sum + a[n%10][m]) % mod;
            n /= 10;
        }
        printf("%lld\n", sum);
    }

    return 0;
}

原因:

代码中没有对结果取模,超过了最大范围可能引起错误,因此加上了这部分内容。

代码预处理的步骤和函数的具体说明提供的解释并不一样。因此对预处理部分做了必要的调整。建议看一遍解释。

以上是你的答案和错误代码的原因,请注意后续维护。

这样:

#include<bits/stdc++.h>
using namespace std;
long long mod=1e9+7;
long long dp[200005][15],a[15],sum[200005];
int main()
{
    int t;
    scanf("%d",&t);
    dp[0][0]=dp[0][1]=1;
    sum[0]=2;
    for(int i=1;i<=200000;i++)
    {
        for(int j=0;j<=9;j++)
        {
            if(j==0) dp[i][j]=(dp[i-1][9])%mod;
            else if(j==1) dp[i][j]=(dp[i-1][0]+dp[i-1][9])%mod;
            else dp[i][j]=(dp[i-1][j-1])%mod;
            sum[i]=(sum[i]+dp[i][j])%mod;
        }
    }
    while(t--)
    {
        long long n;
        int m;
        memset(a,0,sizeof(a));
        scanf("%lld %d",&n,&m);
        while(n){
            a[n%10]++;
            n/=10;
        }
        long long ans=0;
        for(int i=0;i<=9;i++)
        {
            if(a[i]){
            if(m-(10-i)>=0) ans=(ans+a[i]*sum[m-(10-i)])%mod;
            else ans=(ans+a[i])%mod;
            }
        }
        printf("%lld\n",ans);
    }
}