BZOJ4230: 倒计时
4230: 倒计时
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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; }