原题链接:加一 - 题目 - Daimayuan Online Judge
解题思路:首先预处理一下每个数字单独存在时,执行不同加一操作后产生几位数字。用一个二维数组储存,一维是操作数,一维是初始数字。
之后查询时,将原数字拆成每一位单独的数字后直接查数组,O(1)复杂度就能查到这个数字在执行这么多次操作后的位数。
而预处理每一位数字,只需要开一个0-9的数组,储存这十个数字当前分别有几个。在0-8的每一个数字,每执行一次加一操作就是往后挪一位。而9在执行操作后,将里面储存的数量直接赋值给0,用以模拟进位变成10后的那个0。同时也将这个值加给1,代表十位上的1。此时,进位后的数字以及拆成两个单独的数了,接着不断重复即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
long long len[10][200010];//储存0-9每个数在执行不同操作数后的位数
void pre_work(){//预处理函数
long long dp[10],buffer;
for(int i=0;i<=9;i++){
memset(dp,0,sizeof(dp));//初始化
len[i][0]=1;//不执行操作肯定是1位
dp[i]=1;//设置起始点
for(int j=1;j<=200010;j++){
buffer=dp[9];//缓存9的数量
for(int k=9;k>0;k--){
dp[k]=dp[k-1];
}
dp[0]=buffer;//一定不能是累加,因为事实上0的值在+1后已经挪到1了,里面的只是残余的无用数字
dp[1]+=buffer;
for(int k=0;k<=9;k++){//累加这次操作后一共有几位
dp[k]%=mod;
len[i][j]+=dp[k];
len[i][j]%=mod;
}
}
}
return;
}
int main(){
long long t,m,n;
pre_work();//预处理函数
cin>>t;
while(t--){
long long ans=0;
scanf("%lld %lld",&n,&m);
while(n){//循环拆分并查询这个数字在执行m次操作后的位数
ans+=len[n%10][m];
ans%=mod;
n/=10;
}
printf("%lld\n",ans);
}
return 0;
}