题意: 定义f(x)为x所有位的数字乘积,定义g(x)为

while(x!=f(x)){
	x=f(x);
}

的循环次数。

例如x=112333
第一轮
x=112333
f(x)=54
第二轮
x=54
f(x)=20
第三轮
x=20
f(x)=0
第四轮
x=0
f(x)=0
所以得出g(0)=0
g(20)=g(0)+1=1
g(54)=g(20)+1=2
g(112333)=g(54)+1=3

接着我们需要构造出在10^18范围内的正整数a,b且a≠b,使得最大化g(a)+g(b)。

知识点: 思维,递归,构造,打表,记忆化搜索

思路: 显然这题只要放两个数上去,所以你可以直接暴力搜索,如果不想等太久那就加一点记忆化搜索并只枚举递增和2357这四个数。

首先就是求g(x)的过程,因为不断地求g(x)会有很多重复计算的内容,想g(69),g(112333),g(9132)的下一步指向g(54),所以可以采用记忆化搜索保存下来算出下一个f(x)之后先看表中有没有g(54),如果没有接着往下递归。

其次就是因为f(x)求的乘积所以各个位上的数字顺序不重要,所以可以只枚举非递减的数字,来减少开销。接着,因为1乘任何数都是1,比如g(169)和g(69)都等于3,把1放进去只会白占着一个数位所以也不需要枚举1,只要枚举2,3,4,5,6,7,8,9八个数即可。

这里随便举一组有效解

44777779999999999 4446666777777888

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define endl '\n'
using namespace std;
int x[8]={2,3,4,5,6,7,8,9};
string a="0000000000000000000";
map<string,ll> mp;
ll maxn=-1;
int digui(string s,string c)
{
	if(mp[c])
		return mp[c]+1;
	else if(s.compare(c)==0)
		return mp[s]=0;
	else{
		ll ans=1;
		for(int i=0;i<(int)c.size();i++)
			ans*=(c[i]-'0');
		string t=to_string(ans);
		mp[c]=digui(c,t);
		return mp[c]+1;
	}
}
void solve(string s)
{
	ll ans=1;
	for(int i=0;i<(int)s.size();i++)
		ans*=(s[i]-'0');
	string c=to_string(ans);
	mp[s]=digui(s,c);
	maxn=max(mp[s],maxn);
}
void dfs(int f,int n,int l)
{
	if(f==l){
		solve(a.substr(0,l));
//		cout << a.substr(0,l) << endl; 测试递归生成子串是否正确
		return;
	}
	for(int i=n;i<8;i++){
		a[f]=x[i]+'0';
		dfs(f+1,i,l);
	}
}
int main()
{
	cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
	for(int i=1;i<=18;i++){
		dfs(0,0,i);
	}
//	cout << maxn << endl; 用于测试最大的g(x)是否为11
	for(auto p : mp){
		if(p.second==maxn)
			cout << p.first << endl; //这个会输出所有满足g(x)为11的数
	}
	//该程序仅提供了所有g(x)为11的数,想找f(a)!=f(b)的还需要做下筛选。
	return 0;
}