【DBSDFZOJ 4460】666(DP)

来源:互联网 发布:网络推广专员面试 编辑:程序博客网 时间:2024/06/07 22:42

Description

小 π 假期在家无聊,打开了某弹幕直播网站。
突然,有一个精彩的镜头。
小 π 看到了满屏的 6,其中,有 666、也有 666666、也有 6666666666 …
小 π 也想发个弹幕,他打算发 n 个 6。
然而当他按下第一个 6 时,键盘上 6 的键坏了。
这时,弹幕框里只有 1 个 6。
键盘坏了什么的不要紧,先把弹幕发了才是正事。
于是小 π 打算用复制粘贴这类操作来生成这 n 个 6。
具体的说,小 π 电脑的操作系统有唯一的一块剪贴板,初始为空,现在小π 一共有三种操作:
第 1 种操作,全选然后复制。这样会把剪贴板里的内容设置为当前弹幕框内内容。
第 2 种操作,粘贴。会把剪贴板中的内容连接到弹幕框现有的内容后面。
第 3 种操作,backspace。会把在当前弹幕框中删除一个 6。
小 π 很好奇现在生成想要的 n 个 6 至少需要多少次操作,来找到了学信息学竞赛的你。
注意本题时间限制1s

Input

一行一个整数 n。

Output

一行一个整数 ans,表示最少操作次数。

Sample Input 1

0

Sample Output 1

1

Sample Input 2

3

Sample Output 2

3

Data Constraint

其中 6% 的数据,n=2^k,k 为正整数。
其中 24% 的数据,n≤1000。
其中 20% 的数据,内存扩充至768MB。
其中 20% 的数据,时间扩充到3s。
其中 30% 的数据,无特殊限制。
所有数据存在一种划分方法,使得上述范围两两没有交集。
对于 100% 的数据,0≤n≤1000000。

解题思路

考虑dp,f[i]代表从1到i最少需要走几步。状态转移有两种情况,一种是退格,一种是翻倍。可以证明用f[i+j]+j更新f[i]时,j至多需要枚举到3。

代码

#include<bits/stdc++.h>using namespace std;int n,f[1000005];int main(){    scanf("%d",&n);    if(!n)  {printf("1");return 0;}    for(int i=1;i<=n+3;++i)     f[i]=i;    for(int i=1;i<=n;++i){        for(int j=1;j<=3;++j)       f[i]=min(f[i],f[i+j]+j);        for(int j=2;i*j<=n+3;++j)   f[i*j]=min(f[i*j],f[i]+j);    }    printf("%d",f[n]);}

感谢Dilhao大佬的讲解及提示。