CF331C3题解

很牛逼的状态(

贪心比较显然,每次减去数位中最大的数。

证明:如果没减退位那么别的数都做不到,如果减退位了那么下一个要么继续退位要么个位为 \(0\),而别的数两步以内一定没有前者大或者也为 \(0\)

\(f(d,n)\) 表示一个二元组 \((x,y)\),表示在可以使用 \(d\) 这个数位的前提下(就是高位中数位最大的那个),将 \(n\) 减为非正整数需要 \(x\) 步,且这个非正整数为 \(y\)

设有 \(m\) 满足 \(10^m\leq n<10^{m+1}\)。那么每次令最高位减去 \(1\),削掉这一部分的“血皮”,然后继续削剩下的。

于是就有血皮的部分是 \(X=f(\max(d,\lfloor\frac{n}{10^m}\rfloor),n\bmod 10^m)\),剩下的部分就是 \(oth=f(d,10^m\times\lfloor\frac{n}{10^m}\rfloor+X_y)\),结果就是 \(f(d,n)=(X_x+oth_x,oth_y)\)

至于状态总数不会证。不过跑得飞快,在 CF 上面才 30ms。

#include<cstdio>
#include<map>
typedef long long ll;
struct pr{
	ll cnt,num;pr(const ll&cnt=0,const ll&num=0):cnt(cnt),num(num){}
	inline bool operator<(const pr&it)const{return num==it.num?cnt<it.cnt:num<it.num;}
};std::map<pr,pr>f;
inline ll max(const ll&a,const ll&b){return a>b?a:b;}
inline ll Find(const ll&n){ll t(1);while(t*10ull<=n)t*=10;return t;}
inline pr F(const int&d,const ll&n){
	if(n<10)return pr(d||n,n-max(d,n));if(f.find(pr(d,n))!=f.end())return f[pr(d,n)];const ll&m=Find(n);
	const pr&x=F(max(d,n/m),n%m),&oth=F(d,m*ll(n/m)+x.num);return f[pr(d,n)]=pr(oth.cnt+x.cnt,oth.num);
}
signed main(){ll n;scanf("%lld",&n);printf("%lld",F(0,n).cnt);}
posted @ 2022-07-29 19:27  Prean  阅读(20)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};