P2022 有趣的数(二分&数位dp)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2022 有趣的数(二分&数位dp)相关的知识,希望对你有一定的参考价值。

P2022 有趣的数(二分&数位dp)

麻了。

二分答案,然后用数位dp计算 [ 1 , x ] [1,x] [1,x]中有多少个数字字典序 < < < k k k

数位dp的时候开两个数组 a , b a,b a,b x , k x,k x,k

然后就是常规的数位dp操作。

注意如果 d p dp dp数组开到 l i m , l e a d lim,lead lim,lead 则每次 c h e c k check check 都需要初始化 d p dp dp − 1 -1 1

因为这两个变量与 x x x有关。

否则可以只初始化一次。

另外 w , w 1 w,w1 w,w1长度不一定相同,所以 p o s 2 pos2 pos2可能减到 − 1 -1 1。因此让 w 1 w1 w1基数为 20 20 20

// Problem: P2022 有趣的数
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2022
// Memory Limit: 125 MB
// Time Limit: 400 ms
// Date: 2022-07-05 13:23:31
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
ll f[20][40][2][2][2],n,m;
int a[20],w;
int b[40],w1;

ll dfs(int pos, int pos2, bool cmp, bool lim, bool lead) 
    if (pos == 0)
        return (cmp || pos2 > 20) && (!lead);
    if ( f[pos][pos2][cmp][lim][lead] != -1)
        return f[pos][pos2][cmp][lim][lead];
    ll tmp = 0, up = lim ? a[pos] : 9;
    for (int i = 0; i <= up; ++i) 
        bool nxcmp = !(lead && i == 0) && i < b[pos2];
        nxcmp |= cmp;
        if (!cmp && i > b[pos2])
            continue;
        tmp += dfs(pos - 1, pos2 - ((lead && i == 0) ? 0 : 1), nxcmp, lim && i == a[pos], lead && i == 0);
    
    return    f[pos][pos2][cmp][lim][lead] = tmp;

ll check(ll n) 
    w = 0;memset(f, -1, sizeof (f));
    while (n)
        a[++w] = n % 10, n /= 10;
    //printf("w=%d\\n",w);
    ll re = dfs(w, w1, false, true, true);
    return re;

int main()

    scanf("%lld%lld", &n, &m);
    w1 = 20;
    ll l = m > n ? m : n, r = 7e17, ans = 0;
    while (n)
        b[++w1] = n % 10, n /= 10;
    //printf("w1=%d\\n",w1);
    for (; l <= r;) 
        ll mid = (l + r) >> 1, tmp = check(mid);
       // printf("%lld %lld\\n",mid,tmp);
        if (tmp == m - 1) 
            ans = mid; r = mid - 1;
        
        else if (tmp < m - 1) l = mid + 1;
        else r = mid - 1;
    
    printf("%lld\\n", ans);

以上是关于P2022 有趣的数(二分&数位dp)的主要内容,如果未能解决你的问题,请参考以下文章

CCF有趣的数 数位dp

CCF 201312-4 有趣的数 100分(数位dp)

CCF 201312-4 有趣的数 100分(数位dp)

CCF 201312-4 有趣的数 100分(数位dp)

CCF 201312-4有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

poj3208 Apocalypse Someday 数位dp+二分 求第K(K <= 5*107)个有连续3个6的数。