数位DP数位小孩
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数位DP数位小孩相关的知识,希望对你有一定的参考价值。
题目链接:
https://ac.nowcoder.com/acm/contest/23480/D
求 [ l , r ] [l,r] [l,r]区间内满足以下条件数的个数:
1.任意相邻的两个数位之和为素数
2.数位中至少有一个1
3.没有前导0
本题由于l,r
范围只有
1
0
10
10^10
1010,可以dfs暴力做,但是为了复习数位DP,下面用数位DP做。
数位DP经典先预处理f
数组
-
状态表示:
f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]: 满足相临数位之和为素数情况下,共有i
位数,最高位为j
,且数位中存在1
的数的个数
f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0]: 满足相临数位之和为素数情况下,共有i
位数,最高位为j
,且数位中不存在1
的数的个数 -
状态转移:
j=1
时
f [ i ] [ j ] [ 1 ] + = f [ i − 1 ] [ k ] [ 0 ] + f [ i − 1 ] [ k ] [ 1 ] f[i][j][1] += f[i-1][k][0] + f[i-1][k][1] f[i][j][1]+=f[i−1][k][0]+f[i−1][k][1]
f [ i ] [ j ] [ 0 ] = 0 f[i][j][0] = 0 f[i][j][0]=0
j!=1
时
f [ i ] [ j ] [ 1 ] + = f [ i − 1 ] [ k ] [ 1 ] f[i][j][1] += f[i-1][k][1] f[i][j][1]+=f[i−1][k][1]
f [ i ] [ j ] [ 0 ] + = f [ i − 1 ] [ k ] [ 0 ] f[i][j][0] += f[i-1][k][0] f[i][j][0]+=f[i−1][k][0]
注意初始化f
数组时,
f
[
1
]
[
0
]
[
0
]
f[1][0][0]
f[1][0][0]要初始化为1,虽然不满足为素数,但是需要初始化为1,因为后面比如说转移到20(2位数,最高位为2,不存在1,满足相邻数位之和为素数情况)时需要用到。
然后就是转移时,需要额外标记高位是否出现过1
,本题用ok
标记,如果出现过,要额外进行res += f[i+1][j][0]
的操作
最后要加上位数小于给定的数的情况(位数小,整体的数肯定小了)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int f[20][20][2];
bool check(int a,int b)
if(b < 0) return true;
if(a+b==2||a+b==3||a+b==5||a+b==7||a+b==11||a+b==13||a+b==17) return true;
return false;
void init()
f[1][0][0] = 1;
f[1][1][1] = 1;
for(int i=2;i<=9;i++) f[1][i][0] = 1;
for(int i=2;i<=10;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
if(check(j,k))
if(j==1)
f[i][j][1] += f[i-1][k][0] + f[i-1][k][1];
f[i][j][0] = 0;
else
f[i][j][1] += f[i-1][k][1];
f[i][j][0] += f[i-1][k][0];
ll dp(ll x)
if(!x) return 0;
vector<int>nums;
while(x) nums.push_back(x%10),x/=10;
int last = -1;
ll res = 0;
bool ok = false;
for(int i=nums.size()-1;i>=0;i--)
int c = nums[i];
for(int j=(i==nums.size()-1);j<c;j++)
if(check(j,last))
res += f[i+1][j][1];
if(ok) res += f[i+1][j][0];
if(c==1) ok = true;
if(check(c,last)) last = c;
else break;
if(!i and ok) res ++;
for(int i=1;i<nums.size();i++)
for(int j=1;j<=9;j++)
res += f[i][j][1];
return res;
void solve()
init();
ll l,r;
cin>>l>>r;
cout<<dp(r)-dp(l-1)<<"\\n";
int main()
// ios::sync_with_stdio(false);
// cin.tie(0),cout.tie(0);
int t;
// cin>>t;
t = 1;
while(t--) solve();
return 0;
以上是关于数位DP数位小孩的主要内容,如果未能解决你的问题,请参考以下文章