題目:https://ac.nowcoder.com/acm/problem/17867
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
今天是個特殊的日子,CSL和他的小夥伴們圍坐在一張桌子上玩起了明七暗七的遊戲。遊戲規則是這樣的:
一個人報出一個起始數,接下來按照逆時針的順序輪流報數,如果碰到數是7的倍數或含有7,則拍手,下一個人接着報數。直到有一個人報錯了數字或者沒有及時拍手爲止。
玩遊戲嘛,當然得有懲罰。這麼簡單的遊戲對CSL的學霸小夥伴而言實在是太無腦了,輕輕鬆鬆數到上萬根本不在話下。但是對於數學是體育老師教的CSL來說,實在是太難了。快幫他算算什麼時候應該拍手吧。
輸入描述:
輸入兩個整數m和n。(1 ≤ m, n ≤ 1012)
輸出描述:
輸出一個整數,表示m以後第n個需要拍手的數字。
示例1
輸入
30 7
輸出
57
示例2
輸入
56 1
輸出
57
題目要求找到m以後第n個滿足要求的數(被7整除或含有7)。
滿足要求的數我們可以將其逆向思維處理,比如1-7中,含有7或者被7整除的個數爲1,即爲7。也可以看作7個數中減去了不含有7或者被7整除的個數:7-1。數位DP,處理後者更爲簡單,所以可得:x中,滿足題意的數有:x-solve(x)。
dp[cur][sta],sta可以用作處理%7後的狀態。以上爲數位DP的處理。
爲了尋找m後的第n個滿足要求的數,可以用二分查找,即通過mid-solve(mid)和m-solve(m)關於n的關係進行比較,最後輸出查找結果即可。
#include<bits/stdc++.h>
#define INF 1e18
#define inf 1e9
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define IOS ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std ;
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 1e9+7;
int num[100];
ll dp[100][10];
ll dfs(int cur,int sta,bool limit){
if(cur == -1) return sta?1:0;
if(!limit && dp[cur][sta] != -1) return dp[cur][sta];
int up = limit?num[cur]:9;
ll cnt = 0;
for(int i = 0 ; i < up+1 ; i++){
if(i == 7) continue;
cnt += dfs(cur-1,(sta*10+i)%7,limit && i==up);
}
if(!limit) dp[cur][sta] = cnt;
return cnt;
}
ll solve(ll n){
int len = 0;
while(n){
num[len++] = n%10;
n /= 10;
}
return dfs(len-1,0,true);
}
int main(){
IOS;
ll n,m;
while(cin>>m>>n){
memset(dp,-1,sizeof(dp));
ll l = m+1,r = 1e13;
ll cnt = m - solve(m),mid,ans;
while(l<=r){
mid = (l+r)>>1;
if(mid-solve(mid)-cnt>=n) r = mid-1,ans = mid;
else l = mid+1;
}
cout<<ans<<endl;
}
return 0;
}