热身赛题重现江湖

热身赛题重现江湖

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 13   Accepted Submission(s) : 4

Font: Times New Roman | Verdana | Georgia

Font Size:

Problem Description

曾经有人问我,正式比赛会不会有跟热身赛一样的题。我当时说这是个坑。嗯,没错,坑一次。反正,你们都没有在比赛结束后好好思考过这道题吧~~啦啦啦~~啦啦啦~~

一本书的页面从自然数1开始顺序编码直到自然数n。书的页码按照n的位数编排,不足时补充前导数字0。例如,n是149时,第6页用数字006表示,而不是06或6。现在要求你对给定书的总页码n,计算出书的全部页码分别用到多少次数字0,1,2,...,9.

Input

有若干组数据,每组数据一行。 (输入结束标志应该以EOF为准,当scanf函数的返回值为EOF时,表示已经没有数据可以读了)
每行一个数字n。(1≤n≤10^9)

Output

每组输入数据对应10行。分别是0-9的使用次数。
输出完一组数据后,额外输出一个换行。

Sample Input

11
1

Sample Output

10
4
1
1
1
1
1
1
1
1

0
1
0
0
0
0
0
0
0
0

Author

chuyuaem
 

// 位dp ,dp[i][j][k] ,表示 长度 为 i , 以 j 开头 , k 用的次数
// dp[i][j][k] = dp[i-1][u][k] ,如果 j == k ,则还要加上 tt = 10^(i-1) ;

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include<algorithm>
#define maxn 20
#define LL long long
#define mod 1000000007
using namespace std;

LL dp[maxn][maxn][12] ;// len , kaitou , ans
int bit[16] ;
void init()
{
    int i , j , k , u , tt = 10 ;
    memset(dp,0,sizeof(dp)) ;
    for( i = 0 ; i <= 9; i++)
        dp[1][i][i] = 1 ;
    for( i = 2 ; i <= 11 ;i++ ){
        for( j = 0 ; j <= 9 ;j++ )
    {
        for( k = 0 ; k <= 9 ;k++ )
            for( u = 0 ; u <= 9 ;u++ )
             dp[i][j][k] += dp[i-1][u][k] ;
             dp[i][j][j] += tt ;
    }
    tt *= 10 ;
    }
}
void getans( int n )
{
    int i , len = 0 ,k , j ;
    int   a[13] = {0};
    LL tt = 1 , ans[13] = {0};
    // tt 必须是 long long ,因为10^9 时 len = 10 ,但是 tt 计算了11 次
    memset(ans,0,sizeof(ans)) ;
    a[1] = 0 ;
    k = n ;
    while(n)
    {
        bit[++len] = n%10 ;
        n /= 10 ;
        tt *= 10 ;
    }
    tt /= 10 ;
    for( i = len ; i > 1 ;i--)
    {
        k = k%tt ;
        a[i] = k ;
        tt /= 10 ;
    }

    for( i = len ; i >= 1 ;i-- )
    {
        for( k = 0 ; k < bit[i] ; k++ )
        {
            for( j = 0 ; j <= 9 ;j++ )
                ans[j] += dp[i][k][j] ;
        }
        ans[bit[i]] += a[i]+1 ;
    }
    cout << ans[0]-len << endl; // 我们计算的时候把0页码算进去了,所以要把00..00(len 个)去掉
    for( i = 1 ;i <= 9 ;i++ )
        cout << ans[i] << endl;
}
int main()
{
    int i , j ,L , k ;
    int n ;
    init() ;
    //freopen("g.in","r",stdin);
    while( scanf("%d" , &n ) != EOF )
    {
        getans(n) ;
        puts("") ;
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/20120125llcai/p/3443795.html