Description
总所周知,水群是一件很浪费时间的事,但是其实在水群这件事中,也可以找到一些有意思的东西。
比如现在,bx2k就在研究怎样水表情的问题。
首先,bx2k在对话框中输入了一个表情,接下来,他可以进行三种操作。
第一种,是全选复制,把所有表情全选然后复制到剪贴板中。
第二种,是粘贴,把剪贴板中的表情粘贴到对话框中。
第三种,是退格,把对话框中的最后一个表情删去。
假设当前对话框中的表情数是num0,剪贴板中的表情数是num1,
那么第一种操作就是num1=num0
第二种操作就是num0+=num1
第三种操作就是num0–
现在bx2k想知道,如果要得到n(1<=n<=10^6)个表情,最少需要几次操作。
请你设计一个程序帮助bx2k水群吧。
Input
一个整数n表示需要得到的表情数
Output
一个整数ans表示最少需要的操作数
Input示例
233
Output示例
17
解题思路
可以结合题意先思考一个简单问题,对于A=B*k,如果将一个数B转化为A满足这样一个等式,就可以将B复制一次,然后粘贴k-1次,一共操作k次,这样从B便可延伸出k-1个分支,当然这并不是简单的优化。对于数 k=p1∗p2∗p3∗……(pi为质因子) ,这样就可以先将B复制一次粘贴p1-1次,然后将(B*p1)复制一次粘贴p2-1次,这样分支数便减少为(p1+p2+p3+……);但是还存在一种情况,就是对p进行质因子分解的时候只需要2,3,5,7,11这样前5个即可,原因大概就是例如 46=2∗23 ,但是 23=24−1=2∗2∗2∗3−1 ,即将23步优化为了10步,所以在扩展时只扩展 B∗2,B∗3,B∗5,B∗7,B∗11 这样五个节点即可,另外对应退格键的分支是B-1。根据这种扩展规则进行建图,求1-n的最短路即可。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 1000007
bool vis[maxn];
int dis[maxn],n;
int a[]={2,3,5,7,11};
void spfa()
{
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
queue<int>qu;
qu.push(1);
vis[1]=1;
dis[1]=0;
while(!qu.empty())
{
int t=qu.front();
qu.pop();
vis[t]=0;
if(t-1>0&&dis[t-1]>dis[t]+1)
{
dis[t-1]=dis[t]+1;
if(!vis[t-1])
{
qu.push(t-1);
vis[t-1]=1;
}
}
for(int i=0;i<5;i++)
{
if(t*a[i]<maxn&&dis[t*a[i]]>dis[t]+a[i])
{
dis[t*a[i]]=dis[t]+a[i];
if(!vis[t*a[i]])
{
qu.push(t*a[i]);
vis[t*a[i]]=1;
}
}
}
}
printf("%d\n",dis[n]);
}
int main()
{
scanf("%d",&n);
spfa();
return 0;
}