首页 > 代码库 > (DP)codeforces - 710E Generate a String

(DP)codeforces - 710E Generate a String

原题链接:http://www.codeforces.com/problemset/problem/710/E


题意:一个字符串,开始长度为0,目标长度为n,长度+1或-1需要的时间为x,长度*2需要的时间为y,求0到m需要的最少时间。


分析:这题一上来直接写优先队列bfs,然后很愉快的超内存的了。就想别的方法,想了一会没想清晰,感觉可以用记忆化搜索,就往这上面一想,才发现直接dp就行了。

可以很容易发现,奇数肯定是+1或者通过*2逼近并且+1或-1得到。

而偶数只能在+1和翻倍得到。

所以在奇数情况下的状态转移方程为dp[i]=min(dp[i-1]+x,dp[i/2]+x+y,dp[i/2+1]+x+y)

偶数情况下的为dp[i]=min(dp[i-1]+x,dp[i/2]+y)


代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<set>#include<vector>#include<queue>#include<map>#include<list>#include<bitset>#include<string>#include<cctype>#include<cstdlib>using namespace std;typedef long long ll;typedef unsigned long long ull;namespace Math {//最大公约数ll gcd(ll a, ll b) {    return b == 0 ? a : gcd(b, a%b);}//欧拉素数筛int Euler_prime(int *prime, bool *vis, int maxn) {    memset(vis, true, sizeof(vis));    int tot = 0;    for (int i = 2; i < maxn; i++) {        if (vis[i]) prime[tot++] = i;        for (int j = 0; j < tot&&prime[j] * i < maxn; j++) {            vis[i*prime[j]] = false;            if (i%prime[j] == 0) break;        }    }    return tot;}}const int inf = 1 << 30;const ll lnf = 1ll << 60;//-----upstair is template------//const int maxn=1e7;ll dp[maxn];void solve() {    int n,x,y;    scanf("%d%d%d",&n,&x,&y);    fill(dp,dp+maxn,lnf);    dp[0]=0;    for(int i=1;i<=n;i++){        if(i&1){            dp[i]=min(dp[i-1]+x,min(dp[i/2+1]+x+y,dp[i/2]+x+y));        }        else{            dp[i]=min(dp[i-1]+x,dp[i/2]+y);        }    }    printf("%I64d\n",dp[n]);}int main() {#ifndef ONLINE_JUDGE    //freopen("in.txt", "r", stdin);    //freopen("out.txt", "w", stdout);#endif    //iostream::sync_with_stdio(false);    solve();    return 0;}

 

(DP)codeforces - 710E Generate a String