数位小孩(数位dp)

差一点点就提交的代码 值得纪念一下
LINK
在这里插入图片描述
在这里插入图片描述
思路:
先 处 理 f [ i ] [ j ] [ 0 ] 和 f [ i ] [ j ] [ 1 ] 先处理f[i][j][0]和f[i][j][1] f[i][j][0]f[i][j][1];
f [ i ] [ j ] [ 0 ] : 数 字 有 i 位 , 最 高 位 为 j 满 足 相 邻 两 个 数 和 为 素 数 且 数 字 中 不 出 现 1 的 个 数 ; f[i][j][0]:数字有i位,最高位为j满足相邻两个数和为素数且数字中不出现1的个数; f[i][j][0]ij1
f [ i ] [ j ] [ 1 ] : 数 字 有 i 位 , 最 高 位 为 j 满 足 相 邻 两 个 数 和 为 素 数 且 组 合 里 有 1 的 个 数 ; f[i][j][1]:数字有i位,最高位为j满足相邻两个数和为素数且组合里有1的个数; f[i][j][1]ij1
处 理 完 成 后 再 通 过 寻 找 1 − − r 和 1 − − ( l − 1 ) 范 围 内 满 足 题 意 的 个 数 , 再 相 减 即 答 案 。 处理完成后再通过寻找1--r和1--(l-1)范围内满足题意的个数,再相减即答案。 1r1(l1)
f i n d ( ) 思 路 : find()思路: find():(常规数位dp思路)
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const ll N=12;
const ll mod=1e9+7;
const double eps=1e-6;
int f[N][15][2],a[N];
bool pan(int k,int j){//判断两数和是否为素数
	int s=k+j;
	if(s==2||s==3||s==5||s==7||s==11||s==13||s==17)return 1;
	return 0;
}

int find(int x){//计算1--x满足题目要求的个数
	int flag=0;
	if(!x)return 0;
	else if(x<=10)return 1;
	int cnt=0;
	while(x){//存每个位置上的数
		if(!flag&&x%10==1)flag=1;
		a[++cnt]=x%10,x/=10;
	}
	int ans=0,last;int ff=0;
	for(int i=cnt;i>=1;i--){
		int now=a[i];if(now==1)ff=1;
		for(int j=(i==cnt);j<now;j++){
			if(i==cnt||pan(j,last)){//当处于最高位时不需要看相邻
				if(!ff)ans+=f[i][j][1];	
				else ans+=f[i][j][0]+f[i][j][1];//注意这步!!(注意当此位前出现1后f[i][j][0]和f[i][j][1]均满足要求!!!)
			}	
		}
		if(!pan(last,now)&&i!=cnt)break;
		last=now;
		if(i==1&&flag)ans++;
	}
	for(int i=1;i<cnt;i++){
		for(int j=1;j<=9;j++){
			ans+=f[i][j][1];
		}
	}
	return ans;
}
void init(){//预处理f
	f[1][1][1]=1;//为1时满足题目要求
	for(int i=0;i<=9;i++)if(i!=1)f[1][i][0]=1;
	for(int i=2;i<N;i++){
		for(int j=0;j<10;j++){
			if(j==1){
				for(int k=0;k<=9;k++)
				if(pan(k,j))f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1];
			}else
			for(int k=0;k<=9;k++){
				if(k==1){
					if(pan(k,j))
					f[i][j][1]+=f[i-1][k][1];
				}else if(pan(k,j)){
					f[i][j][0]+=f[i-1][k][0];
					f[i][j][1]+=f[i-1][k][1];
				}
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    init();
    int l,r;cin>>l>>r;
    cout<<find(r)<<" "<<find(l-1);
    return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值