称“将一个数上每一位的值$+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 $ .
5
1912 1
5 6
999 1
88 2
12 100
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);
}
}