牛客網 明七暗七 二分法+數位DP

題目: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;
}

 

發佈了148 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章