51Nod 1693 水群(打表确定转移范围优化)

34 篇文章 1 订阅
9 篇文章 0 订阅

1693 水群
基准时间限制:0.4 秒 空间限制:524288 KB 分值: 160 难度:6级算法题 收藏 关注
总所周知,水群是一件很浪费时间的事,但是其实在水群这件事中,也可以找到一些有意思的东西。
比如现在,bx2k就在研究怎样水表情的问题。
首先,bx2k在对话框中输入了一个表情,接下来,他可以进行三种操作。
第一种,是全选复制,把所有表情全选然后复制到剪贴板中。
第二种,是粘贴,把剪贴板中的表情粘贴到对话框中。
第三种,是退格,把对话框中的最后一个表情删去。
假设当前对话框中的表情数是num0,剪贴板中的表情数是num1,
那么第一种操作就是num1=num0
第二种操作就是num0+=num1
第三种操作就是num0–
现在bx2k想知道,如果要得到n(1<=n<=10^6)个表情,最少需要几次操作。
请你设计一个程序帮助bx2k水群吧。
Input
一个整数n表示需要得到的表情数
Output
一个整数ans表示最少需要的操作数
Input示例
233
Output示例
17
QwX (题目提供者)

解题思路:

  首先我们可以把复制和粘贴合并成一个操作,变成长度增加k倍。这样问题就变成了一个最短路问题,每个结点到编号是它k倍的边的长度为k,到比他编号减一的边长度为1,1到N的距离即为答案。
  但是这样时间复杂度很高,回忆矩阵快速幂的过程,实际上我们不需要连接任意倍数,只需要连接倍数是素数的边即可。这样写完打表输出一下中间变量可以发现只用到了2,3,5,7,11,13这几个素数。这样就可以通过这道题了。
   我们还可以继续优化,同样通过打表,我们可以发现连续的减一不超过5个,这样我们就可以使用记忆化搜索来限定减一的次数进行转移。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;

const int MAXN=1000000+3;
int prime[6]={2, 3, 5, 7, 11, 13};
int N, dp[MAXN][2];

int dfs(int x,int flag)//flag==0表示只能有除法得到,flag==1表示可以由除法和减法得到
{
    if(x==1)
        return 0;
    if(dp[x][flag])
        return dp[x][flag];
    dp[x][flag]=INF;
    for(int i=0;i<6;++i)//枚举倍数
        if(x%prime[i]==0)
            dp[x][flag]=min(dp[x][flag], dfs(x/prime[i], 1)+prime[i]);
    if(!flag)
        return dp[x][flag];
    dp[x][0]=dp[x][1];
    for(int i=1;i<6;++i)//枚举减一的个数
        dp[x][1]=min(dp[x][1], dfs(x+i, 0)+i);
    return dp[x][1];
}

int main()
{
    scanf("%d",&N);
    printf("%d\n",dfs(N,1));

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值