天天看點

牛客網題庫——1數位

問題描述:

       給定兩個整數

牛客網題庫——1數位

 和 

牛客網題庫——1數位

,對于所有滿足1 ≤

牛客網題庫——1數位

 ≤

牛客網題庫——1數位

 ≤

牛客網題庫——1數位

≤ 10^9 的

牛客網題庫——1數位

,把 

牛客網題庫——1數位

 的所有約數全部寫下來。對于每個寫下來的數,隻保留最高位的那個數位。求1~9每個數位出現的次數。

輸入描述:

一行,兩個整數  和  (1 ≤  ≤  ≤ 10^9)。
           

輸出描述:

輸出9行。

第 i 行,輸出數位 i 出現的次數。
           

示例1

輸入

1 4

輸出

4
2
1
1
0
0
0
0
0
           

問題轉化:

牛客網題庫——1數位

 , 即

牛客網題庫——1數位

 與

牛客網題庫——1數位

之間的所有整數的所有約數的最高數位數位頻數 等于 1到

牛客網題庫——1數位

之間的所有整數的此項問題解 與 1到

牛客網題庫——1數位

 -1之間的所有整數的此項問題解  的差 

求解思路:    對于問題

牛客網題庫——1數位

, 考慮采用枚舉約數的方式求解,周遊其中所有的整數,對于每一個整數,考量其都可以作為誰的約數,然後計數其被約數的個數,将此個數累加在該數最高位數位頻數上

具體求解方法:

1.  對于整數M,其被約數有M, 2M, 3M, ... (不超過n) ,那麼被約數個數可以這樣求得

牛客網題庫——1數位

2.  在枚舉約數時,鑒于問題求的是最高數位頻數,拟将所有約數以數量級劃分階段進行處理,不妨設其最高數位p和位數q (依題意得q不大于10),這樣每個階段的第一個數可以表示為

牛客網題庫——1數位

,最後一個數可以表示為

牛客網題庫——1數位

那麼對于數位p,其頻數就可以這樣計算了

牛客網題庫——1數位

3.  枚舉約數時,有一個規律值得我們注意,緊鄰的幾個數往往具有相同個數的被約數,充分利用這個規律将會大大加快我們的枚舉速度。對于數M,其後面跟着幾個與其擁有相同個數被約數的整數呢,這個我們要用到數M除n之後的餘數rema,看看餘數裡還夠整數M增加幾個1,設d = 

牛客網題庫——1數位

,則整數M每增一,餘數就減去一個d。照如此算,整數M之後還有

牛客網題庫——1數位

個整數與其擁有相同個數的被約數

#include <bits/stdc++.h>
using namespace std;
typedef long long ll_int;
ll_int l, r;
   
vector<ll_int> solve(ll_int r) {   //設r = 100
    vector<ll_int> ans(10, 0);
    for(ll_int u = 1; u <= 9; ++u) {  //u為最高位數位  設此時u = 3
        for(ll_int v = 1; u * v <= r; v *= 10) {  // u * 10^   ,設此時v = 10
            ll_int s = u * v, e = min(u * v + v - 1, r);    // s = 30 e =min( 39, 100)
            ll_int slip;
            for(ll_int i = s; i <= e; i += slip) {  
                //采用快速求解 此時30 31 32 33的mult是一緻的,故可以不必再去周遊31 32 33,
                ll_int mult = r / i, rema = r % i;   //mult = 3, rema = 10
                slip = 1; slip += min(rema / mult, e - i);   
                //一般情況下采用的都是rema / mult , 目前周遊值每增一,總的就增一個mult,
                //故需要計算餘數中還可容納幾個相同商的約數
                ans[u] += mult * slip;
            }
        }
    }
    return ans;
}
   
int main(void) {
    while(~scanf("%lld%lld", &l, &r)) {
        vector<ll_int> ans1 = solve(l - 1);
        vector<ll_int> ans2 = solve(r);
        for(int i = 1; i <= 9; ++i)
            printf("%lld\n", ans2[i] - ans1[i]);
    }
}
           

連結:https://ac.nowcoder.com/acm/problem/13221

來源:牛客網