17867 明七暗七

数位dp+二分

比较入门的数位dp,快半年没写过拿来练练手。
dp是三维,分别是位置,当前数mod7,是否含有7,前两个很简单,第三位有点迷惑,好像没有什么用,但仔细一想,在低位的时候有时相同的pos和tot也会存在值不一样的情况,比如18和27,一个是4一个是6。所以只有这两个一起才能保证每个值都对应。

//
// Created by acer on 2021/5/11.
//

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int long long
int num[20];
ll dp[20][10][2];

ll dfs(int pos, bool limit, bool h_7, int tot) {
    if (pos < 0) {
        return (h_7 || (tot % 7 == 0));
    }
    if (dp[pos][tot][h_7] != -1 && !limit) return dp[pos][tot][h_7];
    int ub = limit ? num[pos] : 9;
    ll tmp = 0;
    for (int i = 0; i <= ub; ++i) {
        tmp += dfs(pos - 1, limit && i == ub, i == 7 || h_7, (tot * 10 + i) % 7);
    }
    if (!limit) dp[pos][tot][h_7] = tmp;
    return tmp;
}


ll cal(ll x) {
    memset(dp, -1, sizeof(dp));
    memset(num, 0, sizeof(num));
    int pos = 0;
    while (x) {
        num[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos - 1, true, false, 0);
}

signed main() {

    ll m, n;
    while (cin >> m >> n) {
        ll ans = 0;
        ll r = (ll) 1e18;
        ll l = m;
        ll p = cal(m);
        while (l <= r) {
            ll mid = (l + r) >> 1;
            if (cal(mid) - p >= n) {
                ans = mid;
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        cout << l << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值