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个人相撞了 那么则交换两个人的运动方向,直到走到长方形边界停止,问最后每个 ...
随机推荐
- WinForm自动记录从上次关闭位置启动窗体
次功能主要是通过在注册表中读写窗体的Location属性来实现的.在窗体关闭前处理窗体的FormClosed事件,将窗体的Location属性值写入注册表,然后在窗体的Load事件中从注册表中读取保存 ...
- 开源OCR识别库-Tesseract介绍
最近在github上面看到一个开源的ocr文字识别库,感觉效果还可以,所以在这里介绍一下,这个项目的原地址在:https://github.com/tesseract-ocr/tesseract. t ...
- 【C++】继承和组合的概念?什么时候用继承?什么时候用组合?
继承:通过扩展已有的类来获得新功能的代码重用方法 组合:新类由现有类的对象合并而成的类的构造方式 何时用继承?何时用组合? 1.如果二者间存在一个"是"的关系,并且一个类要对另外一 ...
- 复杂的sql参考(3)
SELECT apply.assets_code, apply.loan_apply_code, cust.cust_name, cust.id_no, cust.mobile, platform.p ...
- stm32f103c8串口USART1发送多一字节
用UART写了一段Bootloader代码,遇到了一个很奇怪的现象. 代码如下:简单介绍一下就是先统一配置MCU的IO端口,然后配置串口参数,然后循环发送‘0’和'\r’.16进制是0x30 0x0d ...
- linux查看当前路径命令 pwd
pwd命令能够显示当前所处的路径. 这个命令比较简单,如果有时在操作过程中忘记了当前的路径,则可以通过此命令来查看路径,其执行方式为: # pwd /home/your_username 第一行为运行 ...
- elasticsearch安全重启节点
elasticsearch集群,有时候可能需要修改配置,增加硬盘,扩展内存等操作,需要对节点进行维护升级.但是业务不能停,如果直接kill掉节点,可能导致数据丢失.而且集群会认为该节点挂掉了,就开始转 ...
- Luogu2481 SDOI2010 代码拍卖会 DP、组合
传送门 神仙DP 注意到\(N \leq 10^{18}\),不能够直接数位DP,于是考虑形成的\(N\)位数的性质. 因为低位一定不会比高位小,所以所有满足条件的\(N\)位数一定是不超过\(9\) ...
- C#实现AES加密解密
AES AES 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法 Rijndael(读作rain-dahl)是由美 ...
- C# vb .net实现焦距灰度特效滤镜
在.net中,如何简单快捷地实现Photoshop滤镜组中的焦距灰度效果呢?答案是调用SharpImage!专业图像特效滤镜和合成类库.下面开始演示关键代码,您也可以在文末下载全部源码: 设置授权 第 ...