1. 程式人生 > >[Codeforces#510D] Fox And Jumping

[Codeforces#510D] Fox And Jumping

優先隊列 然而 print map com 都是 ace ring 轉化

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