cf 710 E Generate a String

题意:

开始你有数字$0$,你可以用代价$x$将该数字加$1$或减$1$(当$x > 0$时),或用代价$y$将该数字变为$2x$,那么问得到数字$n$所需的最少代价是多少。

数据范围$1 \leq x, y \leq 10^9$,$1 \leq n \leq 10^7$。

分析:

记得到数字$n$的代价为$f(n)$。

不加证明地给出如下结论:

注:可以通过观察数的二进制表达形式归纳证明下面的结论。

若$x = y$,则

$1^{\circ}$若$n$为偶数,则$f(n) = f(\frac{n}{2}) + y$ $(*)$

$2^{\circ}$若$n$为奇数,则$f(n) = min(f(n - 1), f(n + 1)) + x$ $(\#)$

把$(*)$当作主式,用$(\#)$式作为递推中间项,很容易计算出所有偶数位置对应的$f$值,从而计算出所有$f$值。

当$x, y$大小关系不确定时,我们只需修改偶数情况的更新规则。当$n$为偶数时,为了计算$f(n)$,需要归约到$f(1) = x$,在此过程中如果用到加倍操作,那么在当前位置

用效果必然最好(直观上如此,实际也可证明),否则就不用加倍操作。使用加倍操作后转移到$f(n / 2)$,代价为$y$,而不用加倍操作转移到$f(n / 2)$时代价为$x \cdot \frac{n}{2}$,使用加倍操作当且仅当$y <= x \cdot \frac{n}{2}$,因此将$(*)$更新为:

若$y <= x \cdot \frac{n}{2}$,$f(n) =  f(\frac{n}{2}) + y$

否则$f(n) = n \cdot x$

可以用记忆话搜索来处理答案,空间复杂度$O(n)$,时间复杂度$O(log(n))$。

此外,还可以通过使用队列首先更新花费代价较小的位置来寻找答案,时间复杂度是$O(n)$,类似于$\text{bfs}$的过程。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <functional>
#include <cmath>
#include <iostream>
#include <assert.h>
#pragma comment(linker, "/STACK:102400000,102400000")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define mp std :: make_pair
#define st first
#define nd second
#define keyn (root->ch[1]->ch[0])
#define lson (u << 1)
#define rson (u << 1 | 1)
#define pii std :: pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define type(x) __typeof(x.begin())
#define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
#define FOR(i, s, t) for(int i = (s); i <= (t); i++)
#define ROF(i, t, s) for(int i = (t); i >= (s); i--)
#define dbg(x) std::cout << x << std::endl
#define dbg2(x, y) std::cout << x << " " << y << std::endl
#define clr(x, i) memset(x, (i), sizeof(x))
#define maximize(x, y) x = max((x), (y))
#define minimize(x, y) x = min((x), (y))
using namespace std;
typedef long long ll;
const int int_inf = 0x3f3f3f3f;
const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
const int INT_INF = (int)((1ll << 31) - 1);
const double double_inf = 1e30;
const double eps = 1e-14;
typedef unsigned long long ul;
typedef unsigned int ui;
inline int readint() {
    int x;
    scanf("%d", &x);
    return x;
}
inline int readstr(char *s) {
    scanf("%s", s);
    return strlen(s);
}

class cmpt {
public:
    bool operator () (const int &x, const int &y) const {
        return x > y;
    }
};

int Rand(int x, int o) {
    //if o set, return [1, x], else return [0, x - 1]
    if (!x) return 0;
    int tem = (int)((double)rand() / RAND_MAX * x) % x;
    return o ? tem + 1 : tem;
}
ll ll_rand(ll x, int o) {
    if (!x) return 0;
    ll tem = (ll)((double)rand() / RAND_MAX * x) % x;
    return o ? tem + 1 : tem;
}

void data_gen() {
    srand(time(0));
    freopen("in.txt", "w", stdout);
    int kases = 1;
    //printf("%d\n", kases);
    while (kases--) {
        ll sz = 100000;
        printf("%d\n", sz);
        FOR(i, 1, sz) {
            int o = Rand(2, 0);
            int O = Rand(26, 0);
            putchar(O + (o ? ‘a‘ : ‘A‘));
        }
        putchar(‘\n‘);
    }
}

const int maxn = 1e7 + 10;
ll n, x, y;
ll dp[maxn];

ll cal(ll num) {
    if (dp[num] != -1) return dp[num];
    if (num == 1) return dp[num] = x;
    if (num & 1) return dp[num] = x + min(cal(num - 1), cal(num + 1));
    if ((num >> 1) * x >= y) return dp[num] = y + cal(num >> 1);
    else return dp[num] = num * x;
}

int main() {
    //data_gen(); return 0;
    //C(); return 0;
    int debug = 0;
    if (debug) freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    while (~scanf("%lld%lld%lld", &n, &x, &y)) {
        clr(dp, -1);
        ll ans = cal(n);
        printf("%lld\n", ans);
    }
    return 0;
}

//382 81437847 324871127

时间: 2024-08-06 15:20:45

cf 710 E Generate a String的相关文章

Codeforces 710 E. Generate a String (dp)

题目链接:http://codeforces.com/problemset/problem/710/E 加或者减一个字符代价为x,字符数量翻倍代价为y,初始空字符,问你到n个字符的最小代价是多少. dp[i]表示i个字符的最小代价. 当i为偶数个的时候,由+1或者*2得到. 当i为奇数个的时候,由+1或者*2-1得到. 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm&

【入门dp】E - Generate a String(字符串复制增加删除)

E - Generate a String Time Limit:2000MS     Memory Limit:524288KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 710E Description zscoder wants to generate an input file for some programming competition problem. His input is a st

LeetCode | 1374. Generate a String With Characters That Have Odd Counts生成每种字符都是奇数个的字符串【Python】

LeetCode 1374. Generate a String With Characters That Have Odd Counts生成每种字符都是奇数个的字符串[Easy][Python][字符串] Problem LeetCode Given an integer n, return a string with n characters such that each character in such string occurs an odd number of times. The

【最短路】Codeforces 710E Generate a String

题目链接: http://codeforces.com/problemset/problem/710/E 题目大意: 问写N个字符的最小花费,写一个字符或者删除一个字符花费A,将当前的字符数量翻倍花费B. 题目思路: [动态规划][最短路] [动态规划]: 如果当前x不是2的倍数,那么一定需要单个字符增加或删除,而这个单个操作越靠后答案越优. dp(x)=a+min(dp(x-1),dp(x+1)) 如果当前x是2的倍数,那么有两种情况,一种是通过翻倍的方式获得,一种是通过累加的方式获得.只要比

(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和翻倍得到. 所以在奇

22.Generate Parentheses (String; dfs)

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = 3, a solution set is: "((()))", "(()())", "(())()", "()(())", "()()()" 思路:两个df

CodeForces 710E Generate a String (DP)

题意:给定 n,x,y,表示你要建立一个长度为 n的字符串,如果你加一个字符要花费 x时间,如果你复制前面的字符要花费y时间,问你最小时间. 析:这个题,很明显的DP,dp[i]表示长度为 i 的字符串的最少花费,当 i 是偶数时,要么再加一个字符,要么从i/2中复制,如果为奇数,要么再加1个字符, 要么从i/2先加一个,再复制.即: 奇数 : dp[i] = min(dp[i-1]+x, dp[i/2+1]+y+x); 偶数 : dp[i] = min(dp[i-1]+x, dp[i/2]+y

CodeForces - 710E Generate a String (dp)

题意:构造一个由a组成的串,如果插入或删除一个a,花费时间x,如果使当前串长度加倍,花费时间y,问要构造一个长度为n的串,最少花费多长时间. 分析:dp[i]---构造长度为i的串需要花费的最短时间. 1.构造长度为1的串,只能插入,dp[1] = x. 2.当前串的长度i为偶数,可以 (1)长度为i/2的串加倍:dp[i / 2] + y (2)长度为i-1的串插入一个a:dp[i - 1] + x 3.当前串的长度i为奇数,可以 (1)长度为i/2的串加倍,再加上一个a:dp[i / 2]

codeforces 710E Generate a String(简单dp)

传送门:http://codeforces.com/problemset/problem/710/E 分析: 让你写一个全由"a"组成的长为n的串,告诉你两种操作,第一种:插入一个字母或者删除一个字母需要花费x秒, 第二种:复制现有的串,并加入到原来的穿上,花费y秒,问你最少花费多少时间? 用dp[i]表示需要花费的最少时间,‘ 然后对i为偶数的情况取min(dp[i-1] +x,dp[i/2]+y),当i为奇数时min(dp[i-1] + x, min(dp[i/2+1] + y +