tlqtj
查看原帖
tlqtj
1101254
Louisdlee楼主2024/11/26 10:06

一个不需要用DFS的轻松做法....

实现一个 calc 函数

求出 x ~ 与x位数相同的最大值之间的合法数个数。

比如 x = 1234,那么就是 1234 ~ 9999 之间的合法数的个数。

如果 A,B 位数相同,利用前缀和的思想减一下就行。

如果位数不同,中间的位数是可以直接算出答案的,因为第一个数有7种,剩下的数8种选择。搞一个快速幂就行。

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define INF 1e18

//快速幂
int power(int a, int b) {
    int s = 1;
    while (b) {
        if (b & 1) s = s * a;
        a *= a;
        b >>= 1;
    }
    return s;
}

// a, b 数组存 a,b 的数位
vector<int> a, b;

// 获得 x 的数位数组
vector<int> getdigit(int x) {
    int t = x;
    int cnt = 0;
    vector<int> xx;
    while (t) {
        xx.push_back(t%10);
        t/=10;
    }
    return xx;
}

// 检查x中的数位是否含有4 or 9
bool check(int x) {
    while (x) {
        if (x%10 == 4 or x%10 == 9) return false;
        x/=10;
    }
    return true;
}

/*
    calc 函数计算:
    xxxx ~ 9999(同数位长度)下有多少不含4和9的数
    原理如下:
    以 xxxx = 12345 为例。
    首先算以 2,3,5,6,7,8 开头的数
    2,_,_,_,_ 后面的数随便填,即 8*8*8*8
    3,_,_,_,_ 后面的数随便填,即 8*8*8*8
    5,_,_,_,_ 后面的数随便填,即 8*8*8*8
    7,_,_,_,_ 后面的数随便填,即 8*8*8*8
    ....
    然后第二位,第一位此时必须是 1(因为第一位其他的可能已经被计算完了)
    1,_,_,_,_
    第二位的选择有 3,5,6,7,8
    1,3,_,_,_,_ 后面的数随便填,即 8*8*8
    1,5,_,_,_,_ 后面的数随便填,即 8*8*8
    1,6,_,_,_,_ 后面的数随便填,即 8*8*8
    1,7,_,_,_,_ 后面的数随便填,即 8*8*8
    ....

    然后再看第三位,此时前两位必须是 1,2
    .....

    直到处理完所有位。

    时间复杂度是 O(len * 8 * log(len)),这个 8 可以优化掉,只不过我懒得拆循环。
*/
int calc(int xx) {
    int sum = 0;
    vector<int> tt = getdigit(xx);

    for (int i = tt.size() - 1; i >= 0; i--) {
        for (int j = tt[i]; j <= 9; j++) {
            if (j > tt[i] and j != 4 and j != 9)
                sum += power(8, i);
        }
        // 此时已经算完了从最高位到i位的情况,那么第i位就必须是和tt[i]一样了。如果tt[i]是4or9,直接break即可。
        if (tt[i] == 4 or tt[i] == 9) break;
    }
    //最终看一下 xx 是不是不含 4,9
    if (check(xx)) sum ++;
    return sum;
}


void slove () {
    int A, B;
    cin >> A >> B;

    a = getdigit(A);
    b = getdigit(B);

    // 如果 A, B 位数相同,那么计算一下 A ~ 同位最大值的答案 - B ~ 同位最大值的答案 + B 本身
    if (a.size() == b.size()) {
        int sum = calc(A) - calc(B);
        if (check(B)) sum ++;
        cout << B - A + 1 - sum << endl;
    } else {
        // 如果位数不同,中间的位数没有限制可以直接算,比如有len位,那么开头可以选 7个数,剩下每个数位8种选择,答案就是 7*power(8, len - 1)
        int sum = 0;
        sum += calc(A);
        sum += calc(power(10, b.size() - 1)) - calc(B);

        if (check(B)) sum ++;
        for (int i = a.size() + 1; i < b.size(); i++) {
            sum += 7 * power(8, i - 1);
        }
        cout << B - A + 1 - sum << endl;
    }
}

signed main () {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    slove();
}

2024/11/26 10:06
加载中...