Codeforces D. Little Elephant and Interval(思维找规律数位dp)
题目描述:
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)的更多相关文章
- 找规律/数位DP HDOJ 4722 Good Numbers
题目传送门 /* 找规律/数位DP:我做的时候差一点做出来了,只是不知道最后的 is_one () http://www.cnblogs.com/crazyapple/p/3315436.html 数 ...
- 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- ...
- CF809C(找规律+数位DP)
老年选手需要多写一些思维题qwq. 通过打表很容易发现对于(i,j),值为(i-1)^(j-1)+1,然后本题就没了qwq. 矩阵差分还是很容易想到的,容斥成四个矩阵. 然后看到异或很容易想到三件事: ...
- Tetrahedron(Codeforces Round #113 (Div. 2) + 打表找规律 + dp计数)
题目链接: https://codeforces.com/contest/166/problem/E 题目: 题意: 给你一个三菱锥,初始时你在D点,然后你每次可以往相邻的顶点移动,问你第n步回到D点 ...
- Codeforces 193E - Fibonacci Number(打表找规律+乱搞)
Codeforces 题目传送门 & 洛谷题目传送门 蠢蠢的我竟然第一眼想套通项公式?然鹅显然 \(5\) 在 \(\bmod 10^{13}\) 意义下并没有二次剩余--我真是活回去了... ...
- Codeforces 288E - Polo the Penguin and Lucky Numbers(数位 dp+推式子)
题目传送门 似乎我的解法和官方题解不太一样 纪念自己独立做出来的一道难度 2800 的题. 我们记 \(ans(x)\) 为 \([444...44,x]\) 的答案,显然答案为 \(ans(r)-a ...
- Codeforces 582D - Number of Binominal Coefficients(Kummer 定理+数位 dp)
Codeforces 题目传送门 & 洛谷题目传送门 一道数论与数位 dp 结合的神题 %%% 首先在做这道题之前你需要知道一个定理:对于质数 \(p\) 及 \(n,k\),最大的满足 \( ...
- Codeforces 204A Little Elephant and Interval
http://codeforces.com/problemset/problem/204/A 题意:给定一个[L,R]区间,求这个区间里面首位和末尾相同的数字有多少个 思路:考虑这个问题满足区间加减, ...
- [CodeForces - 848B] Rooter's Song 思维 找规律
大致题意: 有一个W*H的长方形,有n个人,分别站在X轴或Y轴,并沿直线向对面走,第i个人在ti的时刻出发,如果第i个人与第j个人相撞了 那么则交换两个人的运动方向,直到走到长方形边界停止,问最后每个 ...
随机推荐
- Java8 特性
1.jdk8的特性stream().map() 2.Java8中用Lambda表达式的groupBy合并多个相同属性的对象集合 3.Java8 Stream 语法详解 & 用法实例
- kubernetes-dashboard获取令牌登陆
前言:kubernetes核心组件服务启动正常 一.在kubernetes-dashboard.yaml父级文件夹下创建account.yaml文件用于访问kubernetes-dashboard,添 ...
- django缓存相关
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39726347/articl ...
- git lfs指令解决git status显示lib文件被修改,但是没有修改的问题。此时,git checkout没有用。
$ git lfs migrate import --everything --include='*.LIB'https://github.com/git-lfs/git-lfs/issues/283 ...
- 类型的实参与“LPTHREAD_START_ROUTINE”类型的形参不兼容
在使用利用CreateThread创建线程时 struct A { DWORD WINAPI MyThreadFunction(LPVOID) {} void Run() { HANDLE hThre ...
- js中常见字符串类型操作方法(2)
toLowerCase(),toLocalLowerCase(),toUpperCase(),toLocaleUpperCase() var stringValue = "hello wor ...
- Python全栈开发相关课程
Python全栈开发 Python入门 Python安装 Pycharm安装.激活.使用 Python基础 Python语法 Python数据类型 Python进阶 面向对象 网络编程 并发编程 数据 ...
- Shell编程学习(七)
if 条件语句的知识与实践 if 条件语句 if条件语句的语法 单分支结构 第一种 if <条件测试表达式> then 指令 fi 第二种 if <条件测试表达式>; then ...
- MongoDB的安装,mongod和mongo的区别
一. mongoDB安装路径 安装路径(最新4.0.11):https://www.mongodb.com/download-center/community?jmp=nav 建议另外找路径下载,外网 ...
- java基础 String
标准格式:数据类型[] 数组名称 = new 数据类型[] {元素1,元素2,...};省略格式:数据类型[] 数组名称 = {元素1,元素2,...}; Scanner类实现的功能,可以实现键盘输入 ...