数位小孩

传送门

题目描述#

给出一个区间[l,r], 求这个区间内有多少个数字满足如下条件:

  1. 每相邻两个数位和为素数

  2. 其中至少一个数位为 1

  3. 没有前导 0

数据范围#

1lr1010

思路#

典型的 数位DP

计算方式为 f(r)f(l1)

f(x) 代表 [0,x]中符合条件的数字,我们通过从高到低枚举 x 的每一位来进行记忆化搜索即可

不懂 数位DP 的可以去看下这篇blog

CODE
/********************
Author:  Nanfeng1997
Contest: NowCoder
URL:     https://ac.nowcoder.com/acm/problem/233129
When:    2022-03-15 14:21:34

Memory:  524288MB
Time:    2000ms
********************/
#include  <bits/stdc++.h>
using namespace std;
using LL = long long;

LL dp[11][11][2][2][2];
int a[11], cnt;
bool vis[20];

LL dfs(int pos, int last, bool limit, bool lead, bool flag) {
  if(pos == cnt) return flag;
  LL &ans = dp[pos][last][limit][lead][flag];
  if(ans != -1) return ans;  ans = 0;
  for(int i = 0; i <= (limit ? a[pos] : 9); i ++ ) {
    if(lead) {
      ans += dfs(pos + 1, i, limit && i == a[pos], lead && !i, flag || i == 1);
    } else if(vis[last + i]) {
      ans += dfs(pos + 1, i, limit && i == a[pos], lead && !i, flag || i == 1);
    }
  }
  return ans;
}

LL f(LL x) {
  if(!x) return x; 
  cnt = 0;
  memset(a, 0, sizeof a);
  memset(dp, -1, sizeof dp);
  while(x) a[cnt ++ ] = x % 10, x /= 10;
  reverse(a, a + cnt);
  return dfs(0, 0, true, true, false);
}

void solve() {
  vis[2] = 1, vis[3] = 1, vis[5] = 1, vis[7] = 1;
  vis[11] = 1, vis[13] = 1, vis[17] = 1;
  LL l, r; cin >> l >> r;
  cout << f(r) - f(l - 1) << "\n";
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int T = 1; //cin >> T;
  while(T --) solve();

  return 0;
}

posted @   ccz9729  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩