嘘~ 正在从服务器偷取页面 . . .

CF1036C Classy Numbers 题解


CF1036C Classy Numbers 题解

题目链接:CF1036C Classy Numbers

题意:定义一个数字是“好数”,当且仅当它的十进制表示下有不超过\(3\)个数字\(1 \sim 9\)

举个例子:\(4,200000,10203\)是“好数”,然而\(4231,102306,7277420000\)不是

给定\([l,r]\),问有多少个\(x\)使得\(l \le x \le r\),且\(x\)是“好数”

一共有\(T(1 \le T \le 10^{4})\)组数据,对于每次的询问,输出一行一个整数表示答案

\(1 \le l_i \le r_i \le 10^{18}\)

一般数位dp可以用来解决 \(\sum _{i=l}^{r} f(i)\) 的问题,

其中 \(f(i)\) 为与 \(i\) 的数位有关的某个函数或判定式

这题稍微变形了一下,那我们就理所当然地记录一下出现数字的情况

\(f_{i,j}\) 表示满 \(i\) 位数,有 \(j\) 个非 \(0\)

采用记忆化搜索,详见代码

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)()
int num[25],f[25][5];
// u表示当前位数,st表示当前的j,limit表示是否有高位限制
int dfs(int u,int st,bool limit)
{
    if(!u)return 1;
    if(!limit&&f[u][st]!=INF)
        return f[u][st]; // 记忆化
    int up=limit?num[u]:9,ans=0;
    for(int i=0; i<=up; i++)
    {
        if(!i)ans+=dfs(u-1,st,limit&&num[u]==i);
        else if(st!=3)ans+=dfs(u-1,st+1,limit&&num[u]==i);
    }
    if(!limit) f[u][st]=ans; // 只需记录无高位限制的
    return ans;
}
int solve(int x)
{
    int len=0;
    while(x>0)
    {
        num[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,1);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    memset(f,0x3f,sizeof(f));
    int Q;cin >> Q;
    while(Q--)
    {
        int l,r;
        cin >> l >> r;
        cout << solve(r)-solve(l-1) << '\n';
    }
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/rated/solution-cf1036c


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录