版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011528035/article/details/52431028
题意:一个空文本 可以删除一个字符a 也可以增加一个字符a 或者复制整个字符串 问如何到达长度为n
思路:因为一开始没看到有删除功能直接扑了,以为是简单dp,所以直接错了两发T^T。那么只要多判断有删除的就好了。 如果要后面j个点如果要返回i点的话需要的是到val的最小距离-(j-i)*操作1的值,那么我们把他们记在一个队列里,每次拿出用操作1回到原点最小代价的那个就ok,然后再删除掉位置小的就可以。只要优先队列拿出最小的那个,其他的就跟dp一样了
ps:其实好像 有更简单的 因为看题目太粗心了 没看到删除和增加是同一代价...
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <queue>
using namespace std;
#define LL long long
#define MAX 20000010
struct node
{
int pos;
LL val;
bool operator <(const node &a)const
{
return val>a.val;
}
node(int p,LL v)
{
pos=p;
val=v;
}
};
priority_queue<node> q;
LL dp[MAX];
void pop(int p)
{
while(!q.empty()&&q.top().pos<p)
{
q.pop();
}
}
LL Min(LL x,LL y)
{
return x==-1?y:min(x,y);
}
int main()
{
int n;
LL x,y;
scanf("%d%lld%lld",&n,&x,&y);
memset(dp,-1,sizeof(dp));
dp[0]=0;
for(int i=0;i<=n;i++)
{
pop(i);
if(!q.empty())
{
dp[i]=Min(dp[i],q.top().val-i*x);
}
dp[i*2]=Min(dp[i*2],dp[i]+y);
q.push(node(i*2,dp[i*2]+x*i*2));
dp[i+1]=Min(dp[i+1],dp[i]+x);
}
printf("%lld\n",dp[n]);
return 0;
}