处女座和小姐姐(三)(数位dp模板)

 

  • 题目描述
    经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666!
    处女座其实也挺喜欢6这个数字的,实际上他做手环的时候选取的k=6。所以他对于包含数码6的数字极其敏感。每次看到像4567这样的数字的时候他的心就像触电了一样,想起了小姐姐。
    现在你要给处女座展示一系列数字,你想知道他的内心会激动多少次。对于同一个数字,他最多只会激动一次,即如果这个数是66666,他还是只会激动一次。
  • 输入描述:
    一行包括两个数字l,r,表示你给处女座展示的数字范围为[l,r]。
  • 输出描述:
    一行一个整数,表示处女座内心激动的次数。
  • 输入
    10 20
  • 输出
    1
  • 备注:0≤l≤r≤1018

数位dp就是dfs+记忆化数组的过程:
i=4(千位) 0 1 2 3 4 5 6 7 8 9
i=3(百位) 0 1 2 3 4 5 6 7 8 9
i=2(十位) 0 1 2 3 4 5 6 7 8 9
i=1(个位) 0 1 2 3 4 5 6 7 8 9
dfs其实就是模拟数数的过程,我们假设上限是20,dfs的时候我们数到十位的2时,此时2后面的数不用再数了,到个位的时候我们数到0即可(见代码)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
 
typedef long long LL;
const int Max_n=100005;
LL dp[20][2];///i表示当前位,j表示上一位是否是6 
//dp[i][j]表示当前数位没有6的个数 
LL a[20]; 

//if6上一位是否是6,limit上一位是否是上界
LL dfs(int len,bool if6,bool limit){//没有6的个数 
	if(len==0) return 1;//枚举到个位
	if(!limit&&dp[len][if6]) return dp[len][if6];
	//没有到达上限并且当前的数位已经统计过,直接统计已经统计过的即可
	LL cnt=0,up=limit?a[len]:9;//上一位是上界,这一位也是上界,否则上界是9
	for(int i=0;i<=up;++i){//去数当前位能够数的数(0-9)
		if(i==6) continue;//如果当前位是6,剪枝 
		cnt+=dfs(len-1,i==6,limit&&i==a[len]);//上一位是上限,这一位也是上限,下一位一定只数到上限
		//当前位是6说明下一位的上一位是6,(实际这里可以不用记录上一位是否是6(让统计的数只有一位))
	}
	if(!limit) dp[len][if6]=cnt;//不是上界,直接记录数好的即可
	return cnt;
}
LL solve(LL num){
	int k=0;//记录有多少数位 
	while(num){
		a[++k]=num%10;
		num/=10;
	}
	return dfs(k,false,true);
} 
int main(){
    LL l,r;
    scanf("%lld%lld",&l,&r);
	printf("%lld\n",r-l+1-solve(r)+solve(l-1)); //我们需要的是有6的个数
    return 0;
}

转载于:https://www.cnblogs.com/zut-syp/p/10543681.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值