题解 P2602 【[ZJOI2010]数字计数】

吹雪吹雪吹

2018-01-22 20:37:45

Solution

萌新第一次发,想法比较~~独特~~猥琐,众dalao见谅。 如果题目给出的数据比较小,我们自然可以悠闲地按位脱离慢慢数。 但是很遗憾啊,数据很不给情面。 作为新时代的~~懒~~好少年,我并不打算想什么高大上的算法(~~其实是不会写~~),而是准备~~走歪门邪道~~优化。 这里有一个离奇的想法,如果能一次解决成千上万个数字就好了。 接下来,我们经过~~认真打表~~仔细分析发现: N每增长一定值(用1000000比较~~适合嘿嘿嘿~~方便),每个数码的出现次数都有规律地增长(600000个)。 为了方便我们的计算,先将两个边界按照~~笨办法~~朴素算法处理到a\*10^6的形式。 这样一来,我们就可以一次性处理1000000个值(高位的数字解决一下问题不大)。 ```cpp #include<cstdio> #define n50 600000 //随着n61变化而变化 #define n61 1000000 //便于处理 using namespace std; long long a[10],n,m; const long long num[7]={1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000};//10的x次幂 inline long long read() { char ch=getchar();long long ret=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return ret*f; } bool work(long long x) { while(x) { a[x%10]++; x/=10; } } //土办法按位脱离 int main() { // freopen("count.in","r",stdin); // freopen("count.out","w",stdout);//文件什么的不重要 n=read(),m=read(); while(n%1000000!=0&&n<m) { work(n);n++; //把n处理成a*10^6 } while(m%1000000!=0&&m>n) { work(m);m--; //把m处理成a*10^6 } while(n!=m) { for(int i=0;i<10;++i) a[i]+=n50; //直接滚过10^6 int i=0; while(n/num[i]) { a[(n/num[i])%10]+=n61;//注意!高位数字出现了10^6次!而不是传统的600000次! i++; //处理高位 } n+=n61; //向前滚动 } work(m);//处理一下边界 for(int i=0;i<=9;++i) printf("%lld ",a[i]); return 0; } ``` 这种解决方案可适用于更大的数据(只要不爆类型)