数位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)<<" ";
}
}