版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/82734428
原题地址:https://www.nowcoder.com/acm/contest/190/D
思路:我们观察数据范围是 ,那么枚举显然是不合适的,因此我们可以想到数位 .这题我们可以利用数位 求出 内有几个符合要求的数字,但是并不能求出数字是多少.因此我们需要使用二分去判断合法的数字.
所以只需要二分数值 ,判断是否存在那么多的数字就行了.
#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;
}