明七暗七

题目描述 

今天是个特殊的日子,CSL和他的小伙伴们围坐在一张桌子上玩起了明七暗七的游戏。游戏规则是这样的:

一个人报出一个起始数,接下来按照逆时针的顺序轮流报数,如果碰到数是7的倍数或含有7,则拍手,下一个人接着报数。直到有一个人报错了数字或者没有及时拍手为止。

玩游戏嘛,当然得有惩罚。这么简单的游戏对CSL的学霸小伙伴而言实在是太无脑了,轻轻松松数到上万根本不在话下。但是对于数学是体育老师教的CSL来说,实在是太难了。快帮他算算什么时候应该拍手吧。
 

输入描述:

输入两个整数m和n。(1 ≤ m, n ≤ 1012)

输出描述:

输出一个整数,表示m以后第n个需要拍手的数字。

输入

30 7

输出

57

输入

56 1

输出

57
#include<bits/stdc++.h>
using namespace std;
const int N = 20;
typedef long long LL;
LL dim[N], dp[N][10][2];
LL dfs(int pos, int sum, int f, int lim) {
    if (pos < 0) return (!sum || f);
    if (!lim && ~dp[pos][sum][f]) return dp[pos][sum][f];
    int up = lim ? dim[pos] : 9; LL ret = 0;
    for (int i = 0; i <= up; i++) {
        ret += dfs(pos - 1, (sum * 10 + i) % 7, f || i == 7, lim && i == up);
    }
    if (!lim) dp[pos][sum][f] = ret;
    return ret;
}
LL solve(LL x) {
    memset(dp, -1, sizeof(dp));
    memset(dim, 0, sizeof(dim));
    int len = 0;
    while (x) {
        dim[len++] = x % 10;
        x /= 10;
    }
    return dfs(len - 1, 0, 0, 1);
}
int main() {
    LL m, n;
    cin >> m >> n;
    LL st = solve(m);
    LL l = 0, r = 1e18, ret;
    while (l <= r) {
        LL k = (l + r) >> 1;
        LL temp = solve(k);
        if (temp >= st + n) r = k - 1, ret = k;
        else l = k + 1;
    }
    printf("%lld\n", ret);
    return 0;
}
posted @ 2020-08-01 10:00  HighLights  阅读(793)  评论(0)    收藏  举报