zoukankan      html  css  js  c++  java
  • Codeforces510 D. Fox And Jumping

    Codeforces题号:#510D

    出处: Codeforces

    主要算法:map+DP

    难度:4.6

    思路分析:

      题意:给出n张卡片,分别有l[i]和c[i]。在一条无限长的纸带上,你可以选择花c[i]的钱来购买卡片i,从此以后可以向左或向右条l[i]个单位。购买其他卡片后,可以获得更多的跳跃单位。先要求至少花多少元钱才能够任意跳到纸带上任意一个位置。若不行,输出-1.

      首先分析如果只有两个技能的情况。若这两个技能的跳跃长度有最大公约数(x),且满足(x > 1),则一定能跳到任意一个位置。比如(x = 2),那么所有奇数的格子都是跳不到的。如果(x = 3),那么所有非3的倍数都是跳不到的。因此我们可以得到结论,当且仅当(x = 1)时才能够跳到所有的地方。

      联系到多种技能的情况,若所有技能的跳跃长度的最大公约数大于1,那么就像刚才那样一定有格子跳不到。因此要求所选技能的最大公约数必须为1。因此题目可以转化为从n个技能中选取几个,使得其最大公约数为1,并且要让花费尽量小。

      这就可以联系到dp了。令f[i]表示选择一些数并且最大公约数为i时的最小花费。很明显答案就是f[1]。转移也很简单,先扫描1~n,在扫描所有可能的最大公约数j。求出j与l[i]的最小公约数tmp。利用f[j]就可以转移f[tmp]了。(用与不用f[i])

      然而第9个点RE了。

      回想一下过程,由于(l[i] <= 10^9),所以f数组很明显装不下了。可以n只有300,300个卡片能有多少个最大公约数啊。于是我们联想到了map,把f改成一个map就解决问题了。

    代码注意点:

      注意f数组的初始化,f[0]=0,不然就永远进不去循环了……

    Code

    /** This Program is written by QiXingZhi **/
    #include <cstdio>
    #include <map>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    using namespace std;
    typedef long long ll;
    const int N = 310;
    const int INF = 1061109567;
    inline int read(){
        int x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
        return x * w;
    }
    int n,tmp;
    int L[N],c[N];
    map <int, int> f;
    int Gcd(int a, int b){
        if(a < b) return Gcd(b,a);
        if(b == 0) return a;
        return Gcd(b,a % b);
    }
    int main(){
    //    freopen(".in","r",stdin);
        n = r;
        for(int i = 1; i <= n; ++i){
            L[i] = r;
        }
        for(int i = 1; i <= n; ++i){
            c[i] = r;
        }
        f[0] = 0;
        for(int i = 1; i <= n; ++i){
            map <int,int> :: iterator it = f.begin();
            for(; it != f.end(); ++it){
                tmp = Gcd(L[i], it->first);
                if(f[tmp] != 0){
                    f[tmp] = Min(f[tmp], it->second + c[i]);
                }
                else{
                    f[tmp] = it->second + c[i];
                }
            }
        }
        if(f.count(1)){
            printf("%d",f[1]);
        }
        else{
            printf("-1");
        }
        return 0;
    }
  • 相关阅读:
    csp-s模拟99题解
    csp-s模拟9697题解
    csps模拟9495凉宫春日的忧郁,漫无止境的八月,简单计算,格式化,真相题解
    csps模拟93序列,二叉搜索树,走路题解
    csps模拟92数列,数对,最小距离题解
    csps模拟8990部分题解
    csps模拟87888990部分题解
    csps模拟86异或,取石子,优化题解
    csps模拟85表达式密码,电压机制,括号密码题解
    csps模拟83最大异或和简单的括号序列旅行计划题解
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9305782.html
Copyright © 2011-2022 走看看