0
点赞
收藏
分享

微信扫一扫

Add One(数位dp+预处理)

简单聊育儿 2022-02-21 阅读 73
动态规划

题目:You are given an integer n. You have to apply mm operations to it.

In a single operation, you must replace every digit dd 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 mm operations. Since the answer can be very large, print it modulo 10^9+7.

大意:给定一个数n,每进行一次操作,这个数每一位都会+1并以十进制的形式表示,即1912进行一次操作后1->2,9->10,1->2,2->3,就变成21023,求进行m次这种操作后,n这个数的长度。

思路:对于每个位置上的数d,它对它后一位d+1贡献为1(特殊情况9分别对1、0的贡献为1)。那么,我们设dp[i][j]为进行i次操作,数字j的个数。显然,可以推出状态转移方程

当j=0时,dp[i][0]=dp[i-1][9];

当j=1时,dp[i][1]=dp[i-1][0]+dp[i-1][9];

当j!=1&&j!=0,dp[i][j]=dp[i-1][j-1];

我们注意到,如果每次都要dp递推,显然会超时(4e11)。所以我们要预处理一下,把n设为10,m=2e5,这样问题就转化为,这个数到10需要k次。最后可得出答案。

代码:

#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);
	}
}
举报

相关推荐

0 条评论