BZOJ4230: 倒计时

4230: 倒计时

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 20  Solved: 12
[Submit][Status][Discuss]

Description

这是一个特别的倒计时方法。
具体来说,一开始你有一个非负整数n。
每一次操作,你可以从当前的数上减去当前的数某个数位上的数值。当当前数变成0时,倒计时结束。
大概没什么人会对这样不便于使用的倒计时方法充满好奇,但是现在你仍然被要求回答让倒计时结束的最少操作次数。

 

Input

一行一个非负整数n

 

Output

让倒计时结束的最少操作次数

 

Sample Input

24

Sample Output

5

HINT

 

对于全部数据,n<=10^18
 
这就是郑远航眼中的NOIP题2333333
设f[x][len][y]为9999999y,共有len个9,前面最大值为x的数减到0以下的步数,g[x][len][y]为减到0以下剩的值。
然后对于x,我们先逐位减到0,然后就是秀智商与心理素质的时候了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
typedef long long ll;
ll n,f[10][20][10],g[10][20][10],xp[20];
int bit[20],m;
int main() {
    rep(x,1,9) rep(y,0,9) {
        if(x<=y) f[x][0][y]=2,g[x][0][y]=10-x;
        else f[x][0][y]=1,g[x][0][y]=10-x+y;
    }
    xp[0]=1;
    rep(i,1,19) xp[i]=xp[i-1]*10;
    rep(len,1,19) rep(x,1,9) rep(y,0,9) {
        ll res=0,cur=y;
        dwn(i,9,0) res+=f[max(i,x)][len-1][cur],cur=g[max(i,x)][len-1][cur];
        f[x][len][y]=res;g[x][len][y]=cur;
    }
    scanf("%lld",&n);
    if(!n) puts("0");
    else if(n<10) puts("1");
    else {
        ll ans=0,cur=n%10,n0=n;
        while(n0) bit[++m]=n0%10,n0/=10;
        rep(i,2,m-1) {
            int C=0;
            rep(j,i+1,m) C=max(C,bit[j]);
            int k;
            if(i==2) k=bit[i];
            else k=bit[i]-1;
            dwn(j,k,0) ans+=f[max(C,j)][i-2][cur],cur=g[max(C,j)][i-2][cur];
        }
        int k;
        if(m==2) k=bit[m];
        else k=bit[m]-1;
        dwn(i,k,1) ans+=f[i][m-2][cur],cur=g[i][m-2][cur];
        dwn(i,m-3,0) dwn(j,9,1) ans+=f[j][i][cur],cur=g[j][i][cur];
        printf("%lld\n",ans+1);
    }
    return 0;
}
View Code

 

posted @ 2015-08-10 15:47  wzj_is_a_juruo  阅读(397)  评论(0编辑  收藏  举报