数位dp

数位dp
通用解法是一种叫做记忆化搜索的东西
他是一种能够优化搜索的
在dp题中常常考虑暴力做法
但是时间复杂度不够优秀
所以往往把搜过的数记录下来
以便3以后再用
不要62
数位dp入门题
我们可以用dp[i][j]
表示状态发现
dp【i】【j】=西格玛
i-11-k
k!=4或者62之流
但是我们发现假如k!=6
都一样
所以我们就
qwq楼
开dp【41】【2】
表示的是dp【i】【是否为6】
limit表示的是是否为限制位(position)

#include<bits/stdc++.h>
using namespace std;
#define inf 54545
#define inv inline void
#define ini inline int
#define read(x)(int &x)
int dig[inf];
int dp[30][30];
inline int dfs(int cur,bool limit,bool pd)
{
	if(cur<0)return 1;
	if(!limit&&dp[cur][pd]!=-1)
	return dp[cur][pd];
	int cnt=0;
	int up=limit?dig[cur]:9;
	for(int i=0;i<=up;i++)
	{
		if(pd&&i==2)continue;
		if(i==4)continue;
		cnt+=dfs(cur-1,limit&&(i==dig[cur]),i==6);
	}
	if(!limit)
	dp[cur][pd]=cnt;
	return cnt;
}
inline int work(int x)
{
	int kk=x;int cur=0;
	while(kk)
	{
		dig[cur++]=kk%10;
		kk/=10;
	}
	return dfs(cur-1,1,0);
}
int main(){
	memset(dp,-1,sizeof(dp));
	
	
}

记忆化搜索的基本思路
有1000
拆成1-100 101-200 201-300 ****
然后你会发现除了100
之外的都是一样的对于1
所以我们记录下来这个数出现了第几次
所以就会得出
就是说
我们发现对于每个数字的数位而言
就只有
pos(位)以及
sum出现次数
与最后的答案有关系

#include<bits/stdc++.h>
using namespace std;
#define inf 4545
#define inv inline void
#define ll long long
ll dp[100][100];
int num[inf];
inline ll dfs(int pos,bool limit,bool lead,int sum,int d)
{
	if(pos==0)return sum;
	if(dp[pos][sum]!=-1&&lead&&!limit)return dp[pos][sum];
	int up=limit?num[pos]:9;
	ll cnt=0;
	for(int i=0;i<=up;i++)
	{
		cnt+=dfs(pos-1,limit&&(i==up),lead||i,sum+((i==d)&&(i||lead)),d);
	}
    if(!limit&&lead)
    dp[pos][sum]=cnt;
    return cnt;
}
inline ll work(ll x,int d)
{
	memset(dp,-1,sizeof(dp));
	int cur=0;
	while(x)
	{
		num[++cur]=x%10,x/=10;
	}
	return dfs(cur,1,0,0,d);
}
int main(){
	ll l,r;
	cin>>l>>r;
	for(int i=0;i<=9;i++)
	{
		cout<<work(r,i)-work(l-1,i)<<" ";
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值