中国石油大学ACM俱乐部开放训练赛 问题 C: 关于我转生变成史莱姆这档事 找规律 dfs

该博客讨论了《关于我转生变成史莱姆这档事》中的魔素吞噬问题,这是一个寻找最短天数完成魔素吞噬的数学挑战。通过DFS算法,找到满足条件的吞噬序列,即每天吞噬的魔素是前一天的2到9倍。博主分析了问题的输入输出格式,并提出了利用因子和最优剪枝策略来降低时间复杂度的思路。
摘要由CSDN通过智能技术生成

题目描述

关于我转生变成史莱姆这档事这部番剧中,上班族的三上悟因为某个事件而作为史莱姆在异世界转生了。在转生时得到了“大贤者”和“捕食者”这两个独特技能。虽然身为史莱姆,但也想和其他种族建立起友好关系。魔素是异世界里面魔物含有的魔力精华,捕食者这个技能就是吞噬魔素,捕食者的技能要求非常苛刻,如果你第一天吞噬了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

比赛的时候没做出来真的是不应该。
考虑 S = a + a * p1 + a * p1 * p2 + a * p1 * p2 * p3 + . . . . . .
有 S = a * ( 1 + p1 + p1 * p2 + p1 * p2 * p3 + . . . . . .)
其中后面一部分为 S 的因子,且根据题意,这一部分要 >= 3

再考虑
( 1 + p1 + p1 * p2 + p1 * p2 * p3 + . . . . . . )
我们去掉 1 之后还剩下 p1 + p1 * p2 + p1 * p2 * p3 + . . . . . . ,
那么 p1 也要是剩下数的一个因子且 2 <= p1 <= 9

以此类推,过程中再带点最优性剪枝。
实际上这样的时间复杂度已经很小了,因为要保证每次去掉 2–9 中的数是当前数的因子。

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=2100;
int cnt=0;
int fac[maxn];
int minn=inf;

void only(int n)
{
    for(int i=1;i*i<=n;i++)
    {
        if(n%i) continue;
        fac[++cnt]=i;
        if(i*i!=n)
            fac[++cnt]=n/i;
    }
    sort(fac+1,fac+cnt+1);
}

void dfs(int n,int ct)
{
    //cout<<n<<"  "<<ct<<"  "<<pre<<"  "<<ans<<endl;
    if(!n)
    {
        minn=min(minn,ct);
        return ;
    }
    if(ct>=minn) return ;
    if(n<2) return ;
    for(int i=2;i<=9;i++)
    {
        if(i>n) break;
        if(n%i) continue;
        dfs(n/i-1,ct+1);
    }
}

int main(void)
{
    int s;
    scanf("%d",&s);
    only(s);
    for(int i=cnt;i>=1;i--)
        if(fac[i]>=3) dfs(fac[i]-1,1);
    printf("%d\n",minn==inf?-1ll:minn);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值