zjnu1749 PAROVI (数位dp)
Description
The distance between two integers is defined as the sum of the absolute result of subtracting their digits. For example, the distance between the numbers 4561 and 3278 is |4 – 3| + |5 - 2| + |6 - 7| + |1 - 8| = 12. If one of the numbers consists of fewer
digits than the other, we fill it with leading zeroes. Therefore, the distance between the numbers 32 and 5678 is |0 - 5| + |0 - 6| + |3 - 7| + |2 - 8| = 21.
You are given two integers A and B. Calculate the sum of distances between each pair of numbers belonging in the interval [A, B]!
Input
The first and only line of input contains integers A, B (1 ≤ A ≤ B ≤ 10^50000).
Output
The first and only line of output must contain the required number from the text. Given that the number could be extremely large, output answer modulo 1 000 000 007.
Sample Input
Sample Output
题意:定义两个数的距离是这两个数化成十进制后每一位上的数字差的绝对值,如果两个数长度不同,小的那个数用前导零补齐,现在给你两个数A,B,问[A,B]中所有取两个数情况的距离和 。
思路:观察可以发现,[A,B]区间内的距离和是每一位累加得到的,所以我们可以把每一位的sum统计出来。对于每一位,又可以发现,这一位的距离和等于num[0]*num[1]*(1-0)+num[0]*num[2]*(2-0)+...+num[8]*num[9]*(9-8),所以我们要算出每一位上0~9出现的次数。
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 1100000000
#define pi acos(-1.0)
#define maxn 1005
#define MOD 1000000007
#define NN 50000
char s1[50050],s2[50050];
ll num[50050][10],num1[50050][10],num2[50050][10];
ll sumpre[50050],sumsuf[50050];
ll po[50050];
int len;
void init()
{
int i,j;
po[0]=1;
for(i=1;i<=NN;i++){
po[i]=(po[i-1]*10)%MOD;
}
}
void cal1(int len1)
{
int i,j;
sumpre[len1+1]=0;
for(i=len1;i>=1;i--){
sumpre[i]=(sumpre[i+1]*10+s1[i]-'0')%MOD;
}
sumsuf[0]=0;
for(i=1;i<=len1;i++){
sumsuf[i]=(sumsuf[i-1]+(s1[i]-'0')*po[i-1] )%MOD;
for(j=0;j<=9;j++){
if(j+'0'<s1[i]){
num1[i][j]=( (sumpre[i+1]+1)*po[i-1] )%MOD;
}
else if(j+'0'==s1[i]){
num1[i][j]=( sumpre[i+1]*po[i-1]%MOD+sumsuf[i-1]+1 )%MOD;
}
else if(j+'0'>s1[i]){
if(i==len1)num1[i][j]=0;
else num1[i][j]=( sumpre[i+1]*po[i-1] )%MOD;
}
}
}
for(i=len1+1;i<=len;i++){
num1[i][0]=sumsuf[len1]+1;
for(j=1;j<=9;j++)num1[i][j]=0;
}
}
void cal2(int len2)
{
int i,j;
sumpre[len2+1]=0;
for(i=len2;i>=1;i--){
sumpre[i]=(sumpre[i+1]*10+s2[i]-'0')%MOD;
}
sumsuf[0]=0;
for(i=1;i<=len2;i++){
sumsuf[i]=(sumsuf[i-1]+(s2[i]-'0')*po[i-1] )%MOD;
for(j=0;j<=9;j++){
if(j+'0'<s2[i]){ //这里如果当要算的值小于该位的值,那么num2[i][j]=(前面的数+1)*(10^(i-1) )
num2[i][j]=( (sumpre[i+1]+1)*po[i-1] )%MOD;
}
else if(j+'0'==s2[i]){ //这里如果当要算的值等于该位的值,那么num2[i][j]=前面的数*(10^(i-1) )+后面的数+1
num2[i][j]=( sumpre[i+1]*po[i-1]%MOD+sumsuf[i-1]+1 )%MOD;
}
else if(j+'0'>s2[i]){ //这里如果当要算的值大于该位的值,如果这位是最高位,那么num2[i][j]=0,否则num2[i][j]+=前面的数*(10^(i-1) )
if(i==len2)num2[i][j]=0;
else num2[i][j]=( sumpre[i+1]*po[i-1] )%MOD;
}
}
}
for(i=len2+1;i<=len;i++){
num2[i][0]=sumsuf[len2]+1;
for(j=1;j<=9;j++)num2[i][j]=0;
}
}
int main()
{
int n,m,i,j,len1,len2,k;
init();
while(scanf("%s%s",s1+1,s2+1)!=EOF)
{
len1=strlen(s1+1);
len2=strlen(s2+1);
reverse(s1+1,s1+1+len1); //因为算的是[A,B]间的数字个数,所以我们可以用[0,B]-[0,A-1]的,所以要先把A-1。
for(i=1;i<=len1;i++){
if(s1[i]>'0')break;
}
if(i==len1 && s1[i]=='1'){
len1--;
}
s1[i]=s1[i]-1;
for(j=1;j<i;j++){
s1[j]='9';
}
reverse(s2+1,s2+1+len2);
len=max(len1,len2);
cal1(len1);
cal2(len2);
ll sum=0;
for(i=1;i<=len;i++){
for(j=0;j<=9;j++){
num[i][j]=num2[i][j]-num1[i][j];
if(num[i][j]<0)num[i][j]+=MOD;
}
for(j=0;j<=9;j++){
for(k=j+1;k<=9;k++){
sum=(sum+num[i][k]*num[i][j]*(k-j)%MOD )%MOD;
}
}
}
printf("%lld\n",sum*2%MOD);
}
}
/*
1234 9999999
859571453
55 100
10810
*/