题目描述
关于我转生变成史莱姆这档事这部番剧中,上班族的三上悟因为某个事件而作为史莱姆在异世界转生了。在转生时得到了“大贤者”和“捕食者”这两个独特技能。虽然身为史莱姆,但也想和其他种族建立起友好关系。魔素是异世界里面魔物含有的魔力精华,捕食者这个技能就是吞噬魔素,捕食者的技能要求非常苛刻,如果你第一天吞噬了b魔素,那么你第二天可以吞噬第一天的2~9倍(必须是其中一个整数),也就是2b~9b,也就是说,史莱姆在第i天所吞噬的魔素一定是第i-1天的2~9倍,而且还必须是它的整数倍。
作为史莱姆手下的得力助手,哥布林们准备了大量的魔物供主人食用,现在史莱姆已经知道了这些魔物含有S魔素,现在请大贤者合理安排第一天要吞噬和接下来每天需要增加的魔素倍数,好让史莱姆能在最短的天数内恰好吞噬完魔素。由于大贤者要研究“哲学”,无暇顾及这些小事,现在只能请你帮忙,但是大贤者还建议,这些魔素至少要用两天来吞噬。
输入
一个正整数S,代表要吞噬的魔素总量。
输出
一个数,代表要吞噬的天数,如果无解输出-1。
样例输入 Copy
571
样例输出 Copy
5
提示
对于30%数据,有S<=100;
对于70%数据,有S<=107;
对于100%数据,有9<S<=8×108
题目分析:很玄学的一个题,因为数据范围比较大所以一直不敢切,感觉dfs爆搜会超时,看来还是高估出题人给的数据了
首先因为每一天吞噬的魔素必须是前一天的2~9倍,那么我们设 p ∈[ 2 , 9 ] ,第一天吞噬的魔素为 a ,那么往后吞噬的总魔素的数量为:a + a*p1 + a*p1*p2 ... + a*p1*p2*...*pk ,合并同类项之后,就变成了 a * ( 1 + p1 * ( 1 + p2 * ( 1 + ...( 1 + pk ) ) ) ) ,这样也就变成了一个中规中矩的递归的表达式了,对于每次最外面的 a 来说,因为 a * ( 1 + p1 * ( 1 + p2 * ( 1 + ...( 1 + pk ) ) ) ) = sum ,所以 a 一定是题目给出的 s 的一个因子,确定好第一层的因子后,直接dfs搜索就好了,记得一些特定细节的判断就好了,本来以为直接爆搜时间复杂度会高达8^20,肯定会TLE,结果连剪枝都没有,交上去20ms就跑完了,加了个最优性剪枝10ms就跑完了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
vector<int>fac;
int ans=20;//答案肯定不超过20,因为3^20>8e8
void init(int n)
{
for(int i=1;i*i<=n;i++)
{
if(n%i)
continue;
fac.push_back(i);
if(i!=n/i)
fac.push_back(n/i);
}
sort(fac.begin(),fac.end(),greater<int>());//排序是为了忽略因子为自身的这个元素
}
void dfs(int n,int step)
{
if(!n)
{
ans=step;
return;
}
if(step>=ans)//最优性剪枝
return;
for(int i=2;i<=9;i++)
{
if(i>n)
break;
if(n%i)
continue;
dfs(n/i-1,step+1);
}
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<fac.size();i++)//从1开始,忽略自身为因子的元素
dfs(n/fac[i]-1,1);
if(ans==20)
ans=-1;
printf("%d\n",ans);
return 0;
}