题目描述:

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.

思路:

题目是说给一个区间,求这个闭区间内有多少个第一位等于最后一位的数。刚开始,由于数可能会比较大,想到了字符串表示,有找到了一些规律如下:

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

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

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

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

....

这样就先确定区间端点所在的位置,位置中间的整段可以直接求出来。关键在于判断,怎么判断区间端点在整段里前面有多少个数,后面有多少个数。先看只有一个数字的数,然后两个及以上数字的数,先看第一位的元素个数res,再看剩下的位数组成数字的大小tmp和最后一位s[len-1]的大小,如果小于这一部分tmp就为0,大于等于就加上tmp-s[0],再看s[0]与s[len-1]的大小,如果s[0]>s[len-1]就说明包含不了这个最后的数(比如2021,1<2,所以包含不了2022),tmp--,否则tmp就不用减,返回res+tmp。由于这种方法思路复杂,需要很多特判,考虑容易不全,一旦思路转到这个上面,写不对就完了。

字符模拟代码:

#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;
}

当然这题可以有跟简单的考虑。我们要求[l,r]的满足条件的数,不如求[1,l-1],[1,r]的数,最后两个区间相减。同时也不用字符串,直接找规律,直接将数除以10,就得到它在[11,n]中满足条件的数。比如1024除以10就是102,表示[11,1024]里有102个满足条件的数。再加上9就得到[1,1024]的数。

至于为什么会这样,我们依据上面的规律

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

Codeforces D. Little Elephant and Interval(思维找规律数位dp)的更多相关文章

  1. 找规律/数位DP HDOJ 4722 Good Numbers

    题目传送门 /* 找规律/数位DP:我做的时候差一点做出来了,只是不知道最后的 is_one () http://www.cnblogs.com/crazyapple/p/3315436.html 数 ...

  2. 2017年icpc西安网络赛 Maximum Flow (找规律+数位dp)

    题目 https://nanti.jisuanke.com/t/17118 题意 有n个点0,1,2...n-1,对于一个点对(i,j)满足i<j,那么连一条边,边权为i xor j,求0到n- ...

  3. CF809C(找规律+数位DP)

    老年选手需要多写一些思维题qwq. 通过打表很容易发现对于(i,j),值为(i-1)^(j-1)+1,然后本题就没了qwq. 矩阵差分还是很容易想到的,容斥成四个矩阵. 然后看到异或很容易想到三件事: ...

  4. Tetrahedron(Codeforces Round #113 (Div. 2) + 打表找规律 + dp计数)

    题目链接: https://codeforces.com/contest/166/problem/E 题目: 题意: 给你一个三菱锥,初始时你在D点,然后你每次可以往相邻的顶点移动,问你第n步回到D点 ...

  5. Codeforces 193E - Fibonacci Number(打表找规律+乱搞)

    Codeforces 题目传送门 & 洛谷题目传送门 蠢蠢的我竟然第一眼想套通项公式?然鹅显然 \(5\) 在 \(\bmod 10^{13}\) 意义下并没有二次剩余--我真是活回去了... ...

  6. Codeforces 288E - Polo the Penguin and Lucky Numbers(数位 dp+推式子)

    题目传送门 似乎我的解法和官方题解不太一样 纪念自己独立做出来的一道难度 2800 的题. 我们记 \(ans(x)\) 为 \([444...44,x]\) 的答案,显然答案为 \(ans(r)-a ...

  7. Codeforces 582D - Number of Binominal Coefficients(Kummer 定理+数位 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 一道数论与数位 dp 结合的神题 %%% 首先在做这道题之前你需要知道一个定理:对于质数 \(p\) 及 \(n,k\),最大的满足 \( ...

  8. Codeforces 204A Little Elephant and Interval

    http://codeforces.com/problemset/problem/204/A 题意:给定一个[L,R]区间,求这个区间里面首位和末尾相同的数字有多少个 思路:考虑这个问题满足区间加减, ...

  9. [CodeForces - 848B] Rooter's Song 思维 找规律

    大致题意: 有一个W*H的长方形,有n个人,分别站在X轴或Y轴,并沿直线向对面走,第i个人在ti的时刻出发,如果第i个人与第j个人相撞了 那么则交换两个人的运动方向,直到走到长方形边界停止,问最后每个 ...

随机推荐

  1. 双写mq后碰到没有消费问题记录

    上周双写mq后碰到遇到个问题,mq双写的一台机器有produce,另一台一直没有,但是有的那台机器没有消费者,导致另一个服务 一直没有可以消费的mq.原因是 mq在双写初始化配置的时候两个类文件重复了 ...

  2. 有关dfs、bfs解决迷宫问题的个人见解

    可以使用BFS或者DFS方法解决的迷宫问题! 题目如下: kotori在一个n*m迷宫里,迷宫的最外层被岩浆淹没,无法涉足,迷宫内有k个出口.kotori只能上下左右四个方向移动.她想知道有多少出口是 ...

  3. git diff/difftool

    参考好文:使用命令和P4Merge进行diff::https://www.cnblogs.com/cgzl/p/8597066.html git difftool 即可弹出比较工具的界面 哈哈 === ...

  4. JVM中内存的设置和分配(最大内存,总内存,剩余内存的区别)

    1.设置分配的内存大小 -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M -vmargs 说明后面是VM的参数,所以后面的 ...

  5. 词汇AFFRIKE非洲AFFRIKE英语

    affrike 英文单词,含义是非洲,非洲大陆. 中文名:非洲 外文名:affrike 目录 释义 affrike noun名词 非洲,也用做africa 1.Word Origin and Hist ...

  6. @SuppressWarnings注解用法

    @SuppressWarnings注解主要用在取消一些编译器产生的警告对代码左侧行列的遮挡,有时候这会挡住我们断点调试时打的断点. 如图所示: 这时候我们在方法上加上@SuppressWarnings ...

  7. 未能加载文件或程序集 Microsoft.ReportViewer.ProcessingObjectModel, Version=10.0.0.0

    写在前面 整理错误集.某一天在启动项目的时候,出现了未能加载文件或程序集 Microsoft.ReportViewer.ProcessingObjectModel, Version=10.0.0.0错 ...

  8. 把项目通过maven生产源码包和文档包并发布到自己的私服上

    <!-- 把项目通过maven生产源码包和文档包并发布到自己的私服上 执行maven命令,mvn clean package,执行完成后 命令:mvn deploy 就可以发布到你自己的私服上了 ...

  9. dump net core windbg 安装

    安装 1.下载工具windbg 地址:https://www.microsoft.com/zh-cn/p/windbg-preview/9pgjgd53tn86?SilentAuth=1&rt ...

  10. 2019 三七互娱java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.三七互娱等公司offer,岗位是Java后端开发,因为发展原因最终选择去了三七互娱,入职一年时间了,也成为了面 ...