[Codeforces#510D] Fox And Jumping

Posted qixingzhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Codeforces#510D] Fox And Jumping相关的知识,希望对你有一定的参考价值。

Codeforces题号:#510D

出处: Codeforces

主要算法:贪心+优先队列

难度: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;
}

 

以上是关于[Codeforces#510D] Fox And Jumping的主要内容,如果未能解决你的问题,请参考以下文章

Fox And Names CodeForces - 510C

CF510E. Fox And Dinner

codeforce 510C Fox And Names

Codeforces Round #290 (Div. 2) B. Fox And Two Dots(DFS)

Codeforces 512D. Fox And Travelling 题解

CF510B Fox And Two Dots(搜索图形环)