• Educational Codeforces Round 16 E. Generate a String (DP)


    Generate a String

    题目链接:

    http://codeforces.com/contest/710/problem/E

    Description

    zscoder wants to generate an input file for some programming competition problem. His input is a string consisting of n letters 'a'. He is too lazy to write a generator so he will manually generate the input in a text editor. Initially, the text editor is empty. It takes him x seconds to insert or delete a letter 'a' from the text file and y seconds to copy the contents of the entire text file, and duplicate it. zscoder wants to find the minimum amount of time needed for him to create the input file of exactly n letters 'a'. Help him to determine the amount of time needed to generate the input.

    Input

    The only line contains three integers n, x and y (1 ≤ n ≤ 107, 1 ≤ x, y ≤ 109) — the number of letters 'a' in the input file and the parameters from the problem statement.

    Output

    Print the only integer t — the minimum amount of time needed to generate the input file.

    Sample Input

    ``` 8 1 1 8 1 10 ```

    Sample Output

    ``` 4 8 ```
    ##题意: 数num初始时为0,可以用x的花费加一或减一,可以用y的花费乘二,求最小花费变成N.
    ##题解: 规模这么大,要么是找规律,要么是O(n). 最短路什么的肯定不行了. 这里用我为人人的dp来解决:dp[i]: 达到i的最小花费. 枚举i:对于i有三种拓展方向(加一 减一 乘二). 如果直接进行这三种拓展,肯定存在问题:因为存在减一的操作,所以i的最小值可能会由i+1得来. 考虑一个点i,如果它的最小花费是由比i大的点拓展而来的,那么这个点一定是i+1,且它是一个偶数. 证明:首先,因为比i大只能减一操作,所以最小的一定是i+1. 其次,i+1这个数的来源有三种i,i+2,i/2. 肯定不能是i(否者就重复走了),如果是i+2,那么违背上一个条件(i+2连续减两次到达i),所以一定是i/2通过乘二操作得到i. 综上,我们只要在每次更新2*n时,同时更新2*n-1,即可保证每次枚举到i时,dp[i]都是最小. 这题也可以写成"人人为我"的形式,见代码注释.
    ##代码: ``` cpp #include #include #include #include #include #include #include #include #include #include #include #define LL long long #define eps 1e-8 #define maxn 10000100 #define mod 100000007 #define inf 0x3f3f3f3f3f3f3f3f #define mid(a,b) ((a+b)>>1) #define IN freopen("in.txt","r",stdin); using namespace std;

    LL dp[maxn];

    int main(int argc, char const *argv[])
    {
    //IN;

    int n; LL x,y;
    while(scanf("%d %I64d %I64d", &n,&x,&y) != EOF)
    {
        memset(dp, inf, sizeof(dp));
        dp[1] = x;
        for(int i=1; i<=n; i++) {
            dp[i+1] = min(dp[i+1], dp[i] + x);
            if(i*2 < maxn) {
                dp[i*2] = min(dp[i*2], dp[i] + y);
                dp[i*2-1] = min(dp[i*2-1], dp[i*2] + x);
            }
        }
    
        /*
            "我为人人"
            for(int i=1; i<=n; i++) {
                dp[i] = min(dp[i-1]+x, dp[(i+1)/2]+y+(i%2)*x);
            }
        */
    
        printf("%I64d
    ", dp[n]);
    }
    
    return 0;
    

    }

  • 相关阅读:
    Ubuntu终端Terminal常用快捷键
    继承(一)
    c语言中动态数组的建立
    指针的一些小的知识点
    什么是内存地址
    组合(composition)与继承(inheritance)
    重载new和delete
    不要轻易delete void*指针,这样会隐藏比较多的错误。
    内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。
    自动类型转换之全局重载运算符与成员重载运算符
  • 原文地址:https://www.cnblogs.com/Sunshine-tcf/p/5800881.html
Copyright © 2020-2023  润新知