1. 程式人生 > >小米oj 找小"3"(數位dp)

小米oj 找小"3"(數位dp)

- 找小“3”

序號:#40難度:困難時間限制:1000ms記憶體限制:10M

描述

給定一個奇數n,可得到一個由從1到n的所有奇數所組成的數列,求這一數列中數字3所出現的總次數。例如當n=3時,可得到奇數列:1,3,其中有一個數字3,故可得1

輸入

一個奇數。表示n,0<n<9999999999。

輸出

一個整數,表示從 1 到 n 的奇數列中,數字 3 出現的次數。

輸入樣例

1
3
35

 複製樣例

輸出樣例

0
1
7
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int bit[15];
ll n;
ll ans;
ll dp[15];
ll mypow(ll a,ll b)
{
    if(b==0)return 2;
    ll ret=1;
    while(b--)ret*=a;
    return ret;
}
ll get(ll p)
{
    if(p==0)return 1;
    ll tmp=1;ll res=0;
    for(ll i=1;i<=p;i++)
    {
        res+=bit[i]*tmp;
        tmp*=10;
    }
    return res;
}
ll dfs(ll pos,bool flag)
{
    if(flag&&dp[pos]!=-1)return dp[pos];
    if(pos==0)return 0;
    ll x=flag?9:bit[pos];
    ll res=0;
    for(ll i=0;i<=x;i++)
    {
        if(i==3){
            if(flag||i<x){res+=mypow(10,pos-1)/2;}
            else {
                res+=(get(pos-1)+1)/2;
            }
           res+=dfs(pos-1,flag||i<x);
        }
        else {
           res+=dfs(pos-1,flag||i<x);
        }
    }
    if(flag)dp[pos]=res;
    return res;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%lld",&n))
    {
        memset(dp,-1,sizeof(dp));
        int cnt=0;
        while(n)
        {
            bit[++cnt]=n%10;
            n/=10;
        }
        ans=dfs(cnt,0);
        printf("%lld\n",ans);
    }
    return 0;
}