zjnu1749 PAROVI (数位dp)

本文介绍了一种计算两整数间数字距离的方法,并基于此计算指定区间内所有数字对的距离之和。通过分析数字构成特点,提出了一种高效求解算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

1 5

Sample Output

40


题意:定义两个数的距离是这两个数化成十进制后每一位上的数字差的绝对值,如果两个数长度不同,小的那个数用前导零补齐,现在给你两个数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
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值