牛客小白月赛7 D .明七暗七(数位dp+二分)

版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82734428

原题地址:https://www.nowcoder.com/acm/contest/190/D

思路:我们观察数据范围是 1 e 12 ,那么枚举显然是不合适的,因此我们可以想到数位 d p .这题我们可以利用数位 d p 求出 [ 1 , n ] 内有几个符合要求的数字,但是并不能求出数字是多少.因此我们需要使用二分去判断合法的数字.

所以只需要二分数值 x ,判断是否存在那么多的数字就行了.

#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
ll n, m;
int a[maxn];
ll dp[20][20][20];//dp[pos][seven][mod] 当前是第pos位,且是否有7,余数是mod的数量
ll dfs(int pos, int seven, int mod, int limit) {
    if (pos == -1) return  seven || mod == 0;
    if (dp[pos][seven][mod] != -1 && !limit) return dp[pos][seven][mod];
    int up = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= up; i++) {
        ans += dfs(pos - 1,  seven || i == 7, (mod * 10 + i) % 7, limit && i == up);
    }
    if (!limit) dp[pos][seven][mod] = ans;
    return ans;
}
ll solve(ll num) {
    int pos = 0;
    while (num) {
        a[pos++] = num % 10;
        num /= 10;
    }
    return dfs(pos - 1, 0, 0, true);
}
int main() {
    CLR(dp, -1);
    scanf("%lld%lld", &n, &m);
    ll t = solve(n) + m;
    ll left = n + 1;
    ll right = 1e18;
    ll ans;
    while (left <= right) {
        ll mid = (left + right) / 2 ;
        if (solve(mid) >= t) {
            right = mid - 1;
            ans = mid;
        } else left = mid + 1;
    }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/82734428