洛谷 P2602 [ZJOI2010]数字计数

洛谷

第一次找规律A了一道紫题,写篇博客纪念一下。

这题很明显是数位dp,但是身为蒟蒻我不会呀,于是就像分块打表水过去。

数据范围是\(10^{12}\),我就\(10^6\)一百万一百万的打表。

于是我就发现了一些规律。

先献给大家一个打表程序吧~

#include <bits/stdc++.h>
using namespace std;

int main()
{
    long long l,r,cnt[10]={};
    for (long long t=0;t<=999999;++t) {
        l=t*1000000+1;
        r=(t+1)*1000000;
        for (long long i=l;i<=r;++i) {
            long long n=i;
            while (n) ++cnt[n%10],n/=10;
        }
        for (long long i=0;i<=9;++i) cout<<cnt[i]<<' ';
        cout<<endl;
    }
    return 0;
}

这是1~1000000,1000001~2000000,2000001~3000000……的表。

也看一下吧。

488895 600001 600000 600000 600000 600000 600000 600000 600000 600000 
1088895 2200000 1200001 1200000 1200000 1200000 1200000 1200000 1200000 1200000 
1688895 2800000 2800000 1800001 1800000 1800000 1800000 1800000 1800000 1800000 
2288895 3400000 3400000 3400000 2400001 2400000 2400000 2400000 2400000 2400000 
2888895 4000000 4000000 4000000 4000000 3000001 3000000 3000000 3000000 3000000 
3488895 4600000 4600000 4600000 4600000 4600000 3600001 3600000 3600000 3600000 
4088895 5200000 5200000 5200000 5200000 5200000 5200000 4200001 4200000 4200000 
4688895 5800000 5800000 5800000 5800000 5800000 5800000 5800000 4800001 4800000 
5288895 6400000 6400000 6400000 6400000 6400000 6400000 6400000 6400000 5400001 
5888896 7000001 7000000 7000000 7000000 7000000 7000000 7000000 7000000 7000000 
7488895 8600002 7600000 7600000 7600000 7600000 7600000 7600000 7600000 7600000 
8088895 11200001 8200001 8200000 8200000 8200000 8200000 8200000 8200000 8200000 
8688895 12800001 9800000 8800001 8800000 8800000 8800000 8800000 8800000 8800000

这时候你会发现两个规律:

  • 每隔一百万,各个数字都会增加600000个,很神奇。
  • 对于当前的数字i,如果\(\frac{i}{10^k}>0(5<k<13)\),那么\(cnt[(\frac{i}{10^k})~\texttt{mod}~10]+=1000000\)

有了这两大规律,我们就可以轻松处理出\(10^{12}\)的大数据了。

复杂度约为\(O(\frac{r-l+1}{1000000})\)

代码在下面:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    long long a[10]={};
    long long l,r;cin>>l>>r;
    while (l<r&&l%1000000) {
        long long t=l;
        while (t) ++a[t%10],t/=10;
        ++l;
    }
    while (r>l&&r%1000000) {
        long long t=r;
        while (t) ++a[t%10],t/=10;
        --r;
    }
    while (l!=r) {
        for (int i=0;i<10;++i)
            a[i]+=600000;
        long long t=1000000;
        while (l/t&&t<=1000000000000) {
            a[l/t%10]+=1000000;
            t*=10;
        }
        l+=1000000;
    }
    while (r) ++a[r%10],r/=10;
    for (int i=0;i<10;++i) cout<<a[i]<<' ';
    return 0;
}
posted @ 2018-09-04 08:36  fuyan0101  阅读(349)  评论(0编辑  收藏  举报