[51nod1425]减减数

时间:2023-03-09 03:39:47
[51nod1425]减减数

  初始给定一个整数n。每次可以对其做一个操作,这个操作是将n减去他其中的某一位。得到新的一个数字n’,然后继续操作,直到他变成0为止。
  比如24这个例子,24 → 20 → 18 → 10 → 9 → 0

 Input
  单组测试数据。
  第一行有一个整数n(0 ≤ n ≤ 10^12)
 Output
  输出一个整数表示使得n变成0最少的操作步数。.

  呃...今年学车中学noi摸你赛某场的T3....怎么在51nod上才5级啊(掀桌

  十连测那时候抄高分代码才过的...现在终于成功乱(背)搞(诵)出来了...

  没见过的数位DP姿势。

  结构体f[i][j][k].step、.rest:更高的位数最大值为j,将10^(i-1)-k变成<=0的最少步数step、变后的数字为-rest(1<=k<=9)

  g[i].step、.rest:将n的最低i位变成<=0的最少步数step、变后的数字为-rest

  然后转移的时候其实就是调若干次f数组,每次把当前位的数字-1。需要特判.rest等于0的情况。具体见代码吧。

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<bitset>
//#include<ctime>
#define ll long long
#define ull unsigned long long
#define ui unsigned int
#define d double
//#define ld long double
using namespace std;
const int maxn=;
struct zs{ll step;int rest;}f[][][],g[];
int s[],premx[];
//int ff[233333];ll ten[23];
int i,j,k,n,m; int ra,fh;char rx;
inline int read(){
rx=getchar(),ra=,fh=;
while((rx<''||rx>'')&&rx!='-')rx=getchar();
if(rx=='-')fh=-,rx=getchar();
while(rx>=''&&rx<='')ra=ra*+rx-,rx=getchar();return ra*fh;
}
inline int max(int a,int b){return a>b?a:b;}
/*
inline void vio(){
for(i=1;i<=9;i++)ff[i]=1;
for(i=10;i<233333;i++){
int mx=0,j=i;
while(j)mx=max(mx,j%10),j/=10;
ff[i]=ff[i-mx]+1;
// if(i<30)printf("%d %d\n",i,ff[i]);
}
}*/
int main(){
// vio();
ll n;
scanf("%lld",&n);int len=;
if(!n)return puts(""),;
for(ll x=n;x;x/=)s[++len]=x%;
for(i=/*ten[0]=*/;i<=len;i++)premx[i]=max(premx[i-],s[len-i+]);//,ten[i]=ten[i-1]*10; for(i=;i<=;i++)for(j=;j<;j++)f[][i][j]=(zs){,max(,i-(-j))};
g[]=(zs){,premx[len]-s[]}; register int digit,nrest;ll nstep;zs tmp;
for(i=;i<=len;i++){
if(i<len){
for(j=;j<=;j++)for(k=;k<;k++){
for(digit=,nstep=,nrest=k;digit>=;digit--){
tmp=f[i-][max(j,digit)][nrest],
nstep+=tmp.step,nrest=tmp.rest;
if(!nrest&&digit)nstep++,nrest=max(j,digit);
}
f[i][j][k]=(zs){nstep,nrest};
//if(!j)printf("%d %d %d (%lld,%d) ff:%d\n",i,j,k,f[i][j][k].step,f[i][j][k].rest,ff[ten[i]-k]);
}
} nstep=g[i-].step,nrest=g[i-].rest;
if(!nrest&&s[i])nstep++,nrest=premx[len-i+];
for(digit=s[i]-;digit>=;digit--){
tmp=f[i-][max(premx[len-i],digit)][nrest],
nstep+=tmp.step,nrest=tmp.rest;
if(!nrest&&digit)nstep++,nrest=max(premx[len-i],digit);
}
g[i]=(zs){nstep,nrest};
}//printf("%lld %d\n",g[len].step,ff[n]);
printf("%lld\n",g[len].step);
}