Codeforces D. Little Elephant and Interval (thinking to find the law digit dp)

Subject description:

Little Elephant and Interval

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

The Little Elephant very much loves sums on intervals.

This time he has a pair of integers l and r (l ≤ r). The Little Elephant has to find the number of such integers x (l ≤ x ≤ r), that the first digit of integer x equals the last one (in decimal notation). For example, such numbers as 101, 477474 or 9 will be included in the answer and 47, 253 or 1020 will not.

Help him and count the number of described numbers x for a given pair l and r.

Input

The single line contains a pair of integers l and r (1 ≤ l ≤ r ≤ 1018) — the boundaries of the interval.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use cin, cout streams or the %I64d specifier.

Output

On a single line print a single integer — the answer to the problem.

Examples

Input

Copy

2 47

Output

Copy

12

Input

Copy

47 1024

Output

Copy

98

Note

In the first sample the answer includes integers 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44.

Ideas:

Entitled to say an interval, find the number of the first number is equal to the last one in this closed interval. At first, since the number may be relatively large, think of the string representation, we have found some rules as follows:

1---------9---------1*9

11--------99--------1*9

101---------999------10*9

1001-----------9999------100*9

....

This will determine the position of the first end section is located, the whole can find out directly the middle position. The key is determined, how to determine the front end section in the whole number of the number, followed by how many. Look at only a few digits, then the number of two or more digits, the first look at res number of elements, look at the remaining digits and the last digit of a tmp size s [len-1] size, if it is smaller than 0 this part tmp, tmp-plus greater than or equal to s [0], s look and size s [0] [len-1], and if s [0]> s [len- 1] will not be described comprises the last number (such as 2021,1 <2, so not comprising 2022), tmp--, would not otherwise tmp Save return res + tmp. Since this method complex thinking, we need a lot of special judge, consider incomplete easy, once thought to the above, do not write on the end.

Character simulation code:

#include <iostream>
#include <string>
using namespace std;
string l,r;
long long len1;
long long len2;
long long ans = 0;
long long q_mod(long long a,int b)
{
    long long res = 1;
    if(b==-1)
    {
        return 1;
    }
    while(b)
    {
        if(b&1) res = res*a;
        a = a*a;
        b>>=1;
    }
    return res;
}
long long sub(string s)
{
    //cout << "s " << s << endl;
    int len = s.size();
    if(len==1)
    {
        return s[0]-'0';
    }
    long long res = 0;
    res = (s[0]-'1')*q_mod(10,len-2);
    long long tmp = 0;
    for(int i = 1;i<len;i++)
    {
        tmp = 10*tmp+s[i]-'0';
    }
    //cout << "tmp " << tmp << endl;
    if(tmp>=s[0]-'0')
    {
        tmp-=(s[len-1]-'0');
        tmp /= 10;
        if(s[len-1]>=s[0])
        {
            tmp+=1;
        }
    }
    else
    {
        tmp = 0;
    }
    return res+tmp;
}
int main()
{
    cin >> l >> r;
    len1 = l.size();
    len2 = r.size();
    for(int i = len1+1;i<len2;i++)
    {
        ans += 9*q_mod(10,i-2);
    }
    long long tmp1 = sub(l);
    if(l[0]==l[len1-1]) tmp1--;
    long long tmp2 = sub(r);
    //cout << "tmp1 " << tmp1 << " tmp2 " << tmp2 << endl;
    //cout << "q_mod " << 9*q_mod(10,len1-2) << endl;
    if(len1==len2)
    {
        ans += tmp2-tmp1;
    }
    else
    {
        ans += (9*q_mod(10,len1-2)-tmp1)+tmp2;
    }
    cout << ans << endl;
    return 0;
}

Of course, this problem can be with the simple consideration. We claim number [l, r] satisfies the condition, and will not find [1, l-1], [1, r] number, the last two sections subtracted. Also do not string directly to the law, divided by 10 directly, it is obtained that satisfy the condition in [11, n] in number. 1024 divided by 10 is such as 102, represents a [11,1024] satisfying the condition, there are 102 numbers. 9 is obtained together with [1, 1024] number.

As to why this is so, we are above the law in accordance with

1---------9---------1*9

11--------99--------1*9

101---------999------10*9

1001-----------9999------100*9

....

发现[11,n]中满足条件的数是\(num = 10^{len(n)-1}-1\),如果n=99...9的话,其中len(n)是n的长度。我们可以发现99999/10=9999,实际上就是\(num=10^4-1\)。其实一个数满足首末元素相等的话,我们除以十就忽略掉了末元素。实际上除以十就是上一种思路的简化表示。上一种思路中的res与tmp部分做的就是这个事。举个栗子:1024,1024/10=102,这102是怎么来的呢:999/10+2-0+1,999/10表示前面整段满足条件的个数,2-0+1做的就是上一种思路做的。

所以这一点后,实现就简单了,思路也简单了。注意的是一位数的特判,直接返回即可。

找规律代码:

#include <iostream>
using namespace std;
long long l,r;
long long cal(long long n)
{
    long long ans = n/10;
    if(n<10) return n;
    ans += 9;
    int tmp = n%10;
    while(n>=10)
    {
        n /= 10;
    }
    if(n>tmp)
    {
        ans--;
    }
    return ans;
}
int main()
{
    cin >> l;
    cin >> r;
    cout << cal(r)-cal(l-1) << endl;
    return 0;
}

然后,这道题是跟数的组成有关的,因此可以考虑数位dp,求出[1,l-1]与[1,r]的满足条件的数,相减即可,思路与上一种类似。

dp[pos] [num]表示处理到第pos位,第一位是num的满足条件的数的个数。代码中st表示前一位数,lead表示有无前导零,limit表示对当前位有无限制。注意数据范围。

数位dp代码:

#include <iostream>
#include <memory.h>
using namespace std;
long long dp[20][10];
int x[20];
int cnt;
long long dfs(int pos,int num,int st,int limit,int lead)
{
    if(pos<1) return num==st;
    if(dp[pos][num]!=-1&&!limit&&!lead) return dp[pos][num];//记忆化搜索
    int up = limit?x[pos]:9;
    long long res = 0;
    for(int i = 0;i<=up;i++)
    {
        if(lead&&(i==0))//若有前导零,这一位也是零,继续处理下一位
        {
            res += dfs(pos-1,0,st,i==up&&limit,lead);
        }
        if(lead&&i)//若有前导零,这一位不是零,以这一位为数的第一位
        {
            if(1==pos) st = i;//如果这是数的唯一一位,也是最后一位,把st设为i
            res += dfs(pos-1,i,st,limit&&i==up,!lead);
        }
        if(!lead)//若无前导零,正常递归
        {
            res += dfs(pos-1,num,i,limit&&i==up,lead);
        }
    }
    if(!limit&&!lead) dp[pos][num] = res;//记录
    return res;
}
long long Count(long long n)
{
    cnt = 0;
    while(n)
    {
        x[++cnt] = n%10;
        n/=10;
    }
    /*for(int i = 1;i<=cnt;i++)
    {
        cout << x[i] << " ";
    }
    cout << endl;*/
    return dfs(cnt,0,-1,1,1);
}
int main()
{
    long long l,r;
    cin >> l >> r;
    memset(dp,-1,sizeof(dp));
    //cout << "rr " << Count(r) << endl;
    //cout << "ll " << Count(l-1) << endl;
    cout << Count(r)-Count(l-1) << endl;
}

参考文章:

luminous11,CodeForces 204A Little Elephant and Interval,https://blog.csdn.net/luminous11/article/details/43971413

My_ACM_Dream,codeforces 204A Little Elephant and Interval (数位dp),https://blog.csdn.net/my_acm_dream/article/details/43373419

Mathison,数字组成的奥妙——数位dp,https://www.luogu.org/blog/virus2017/shuweidp

wust_wenhao,数位dp总结 之 从入门到模板,https://blog.csdn.net/wust_zzwh/article/details/52100392

Guess you like

Origin www.cnblogs.com/zhanhonhao/p/11307760.html
Recommended