不要62(数位DP)

不要62(数位DP)

第一个数位 d p dp 题,发现去年用打表前缀和过的。。

思路1:记忆化搜索,具体看代码吧。

#include<bits/stdc++.h>
using namespace std;
const int N=12;
int dp[N][2],digit[N];	//digit[i]保存第i位的数字(从1开始) 1是最低位. 
int dfs(int len,int pre,int sta,int ismax){	//dp[i][0]表示i位数且前一位不是6的答案 
	int ans=0,maxx;	//len当前位数长度,pre当前位的前一位,前一位是否为6,该位是否原数
									//dp[i][1]表示i位数且前1位是6的答案. 
	if(!len) return 1;//递归到最深处 0位数直接返回. 
	if(!ismax&&~dp[len][sta]) return dp[len][sta];//记忆化. 
	maxx=ismax?digit[len]:9;
	for(int i=0;i<=maxx;i++){
		if(i==4||(pre==6&&i==2)) continue;
		ans+=dfs(len-1,i,i==6,ismax&&i==maxx);
	}
	if(!ismax) dp[len][sta]=ans;
	return ans;
}
int solve(int n){
	int len=0;
	while(n){
		digit[++len]=n%10;
		n/=10;
	}
	return dfs(len,-1,0,1);
}
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)&&(n||m)){
		memset(dp,-1,sizeof dp);
	printf("%d\n",solve(m)-solve(n-1)); 
	}
} 

思路2 : d p dp

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
int dp[N][10],n,m,d[N];
void init(int n){
	dp[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=0;j<10;j++)
			for(int k=0;k<10;k++)
				if(j!=4&&!(j==6&&k==2))
					dp[i][j]+=dp[i-1][k]; 
}
int solve(int n){
	int len=0,ans=0;
	while(n){
		d[++len]=n%10,n/=10;
	}
	d[len+1]=0;
	for(int i=len;i>=1;i--){
		for(int j=0;j<d[i];j++)
		if(!(d[i+1]==6&&j==2))	//这一句判断不能省略,4可以省略因为在init已经判断过了. 
			ans+=dp[i][j];
		if(d[i]==4||(d[i+1]==6&&d[i]==2)) break;
	}
	return ans;
}
int main(){
	init(7);
	while(~scanf("%d%d",&n,&m)&&(n||m)){
		printf("%d\n",solve(m+1)-solve(n));//注意这里solve(x)是计算[0,x-1]的满足条件的个数. 
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/107631258
今日推荐