HDOJ 6659 Acesrc and Good Numbers

题目地址
Problem Description
Acesrc is a famous mathematician at Nanjing University second to none. Playing with interesting numbers is his favorite. Today, he finds a manuscript when cleaning his room, which reads

… Let f(d,n) denote the number of occurrences of digit d in decimal representations of integers 1,2,3,⋯,n. The function has some fantastic properties …

… Obviously, there exist some nonnegative integers k, such that f(d,k)=k, and I decide to call them d-good numbers …

… I have found all d-good numbers not exceeding 101000, but the paper is too small to write all these numbers …

Acesrc quickly recollects all d-good numbers he found, and he tells Redsun a question about d-good numbers: what is the maximum d-good number no greater than x? However, Redsun is not good at mathematics, so he wants you to help him solve this problem.

Input
The first line of input consists of a single integer q (1≤q≤1500), denoting the number of test cases. Each test case is a single line of two integers d (1≤d≤9) and x (0≤x≤1018).

Output
For each test case, print the answer as a single integer in one line. Note that 0 is trivially a d-good number for arbitrary d.

Sample Input
3
1 1
1 199999
3 0

Sample Output
1
199990
0

  • 赛后发现把某个int改成longlong就过了,艹,不开ll见祖宗
  • 思路
    首先我们要解决的是计算n以内d的出现次数,方法可以用数位dp或者找规律推数学公式,恰好我以前看过一篇博客,讲了数学公式的推导,传送门 ,里面讲的很详细了,我也不多说废话。接下来就是找答案了,显然如果f(d,n)=n答案就为n。否则,让n-=max(1,abs(f(d,n)-n)/18)。因为*f(d,n)f(d,n-1)*的差最多为18。显然,n和abs(f(d,n)-n)/18的数量级是一样的,故循环的次数不大。
  • 代码
#include
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
ll cal(ll n, ll x) {
    ll cnt = 0, k;
    for (ll i = 1;k = n / i;i *= 10) {
        cnt += (k / 10) * i;
        int cur = k % 10;
        if (cur > x) {
            cnt += i;
        } else if (cur == x) {
            cnt += n - k * i + 1;
        }
    }
    return cnt;
}
int main(){
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    ll d,x;
    while(T--){
        cin>>d>>x;
        while(1){
            ll num=cal(x,d);
            if(num==x){
                cout<<x<<endl;
                break;
            }
            x-=max(1ll,abs(num-x)/18);
        }
    }
}

你可能感兴趣的:(刷题记录)