\(\text{C - 1, 2, 3 - Decomposition}\)

解法

定义一个数为好数当且仅当它由 \(1,2,3\) 组成,\(f(i)\) 就是 \(i\) 的答案。

分而治之 的思想挺妙的,但我压根没想到。考虑将 \(n\) 分解成 \(10p+r\) 的形式(并非除数与余数),可以想到,\(f (p)\) 分解的每个好数再乘以 \(10\) 加上 \(1,2,3\) 就又是一个好数。

基于此,不妨令 \(k\le r\le 3k\),那么如果 \(f(p)\le k\) 就意味着一定能找出解,即有 \(1,2,3\) 与每个好数匹配。注意不满足条件也不意味着一定无解,这点下文详细再谈。

考虑时间复杂度。

打表发现\(f(n)\le 5\)。现在我们加以证明:转化一下,现在只用证明 \(n\) 一定能被分解成这样的 \(p,r\) 满足 \(f(p)\le 5\)\(5\le r\le 15\)。我们可以归纳证明。首先当 \(i\le 15\) 时一定有 \(f(i)\le 5\),对于其它情况,你发现 \(r\) 的个位取值取到了 \([0,9]\) 中每个数字!而我们又可以任意减去 \(10\) 的倍数,所以结论得证。

既然我们证明这样构造一定有解,就不用考虑不满足构造仍有解的情况了。

由于 \(f(n)\le 5\)\(5\le r\le 15\),我们容易得出对于每个 \(n\)\(p\) 至多有两种取值,而迭代次数由于每次除以 \(10\) 非常小。所以这是可过的。

代码

#include <cstdio>

#define print(x,y) write(x),putchar(y) 

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}

#include <map>
using namespace std;

typedef long long ll;

map <ll,int> mp;

int f(ll n) {
	if(mp.count(n)) return mp[n];
	int ans=-1;
	for(ll k=1;k<=n;++k) {
		for(ll i=k;i<=k*3;++i) {
			if(n-i<0) break;
			if((n-i)%10==0) {
				if(f((n-i)/10)<=k) {
					ans=k; break;
				}
			}
		}
		if(~ans) break;
	}
	return mp[n]=ans;
}

int main() {
	mp[0]=0;
	for(int T=read(9);T;--T) {
		ll n=read(9ll);
		print(f(n),'\n');
	}
	return 0;
}
posted on 2021-07-23 08:55  Oxide  阅读(63)  评论(0编辑  收藏  举报