能夠到這裏測。。嘿嘿嘿ios
題目:算法
【問題 描述 】 小 Q 是一名酷愛鉤爪的忍者, 最喜歡飛檐走壁的感受, 有一天小 Q 發現一個練習使用鉤 爪的好地方,決定在這裏大顯身手。 場景的天花板能夠被描述爲一個無窮長的數軸, 初始小 Q 掛在 原點上。 數軸上有 N 個坐 標爲整數的圓環供小 Q 實現鉤爪移動。具體操做爲:小 Q 能夠將鉤爪掛到圓環上,進而盪到 關於圓環座標 軸 對稱的位置。例如小 Q 在 3,圓環在 7,則小 Q 能夠經過該圓環移動到 11。 如今一個問題難倒了小 Q,如何判斷本身可否到達某個整點呢? 【 輸入格式 】 第一行兩個整數 N,M,表示圓環的數量和詢問組數 接下來一行共 N 個整數描述每一個圓環的座標(可重複) 接下來 M 行每行包含一個整數描述詢問 【 輸出格式 】 共 M 行對應 M 個詢問,若小 Q 能移動到目標點,輸出 Yes,不然輸出 No 【 樣例輸入 】 2 2 1 3 3 4 【 樣例輸出 】 No Yes 【 數據範圍和註釋 】 對於 30%的數據,M≤N≤10,輸入座標絕對值均小於 1000。 對於 60%的數據,M≤N≤5000。 對於 100%的數據,M≤N≤100000,輸入座標絕對值均小於 10^18。
對於30%的分數ide
可使用暴力記憶化搜索得出答案。即維護每一個座標是否可達,繼而進行搜索。spa
對於60%的分數code
經過觀察可知設當前座標爲x,則經過座標爲a的圓環可移動到2a-x處。連續經過兩個圓環(a,b)能夠移動到x+(2b-2a)處。blog
先以移動步數爲偶數狀況考慮簡化版問題:設圓環座標爲a[1]~a[n],對於任意兩個圓環,可由座標x變爲x+2(a[j]-a[i]),題目轉化爲對於N^2個數其中b[i,j]=2(a[j]-a[i]),經過有限次加減運算可否由x=0變化至目標。get
根據廣義裴蜀定理以及擴展歐幾里得相關原理可知,當且僅當目標爲gcd的倍數時有解。故預處理出所有可能的2(a[j]-a[i]),求出其最大公約數,在判斷目標是否爲gcd的倍數便可。io
對於奇數的狀況,能夠經過枚舉第一步的方案轉化爲偶數的狀況,即維護一個set表示0步或1步可達點集(mod gcd意義下),再查詢目標點在mod gcd下是否屬於這個集合便可。複雜度瓶頸在於N^2個數求gcd。event
對於100%的分數class
經過歐幾里得算法的性質與更相減損術可知gcd(a,b)=gcd(a-b,b)。設p1={2*(a[i]-a[1])|i>1}的最大公約數,設p2={2*(a[i]-a[j])}的最大公約數,易知p1>=p2(由於p1比p2約束寬鬆)。而對於任意i,j因爲p1同時是2*(a[i]-a[1])、2*(a[j]-a[1])的約束,那麼p1也必定是任意2*(a[i]-a[1])-2*(a[j]-a[1])=2*(a[i]-a[j])的約數,故p1<=p2。綜上所述p1=p2,這樣就不須要N^2個數同時求gcd了,只求p1便可,可得到滿分。
附贈std:
#include <iostream> #include <cstdio> #include <set> using namespace std; const int N=200010; int n,m; long long a[N],GCD=0; set<long long> Set; long long gcd(long long a,long long b) { return b?gcd(b,a%b):a; } long long qabs(long long x){return x<0?-x:x;} int main() { // freopen("ninja.in","r",stdin); // freopen("ninja.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=2;i<=n;i++) GCD=gcd(2LL*qabs(a[i]-a[1]),GCD); if(GCD==0)GCD=1000000000LL*1000000000LL; Set.insert(0LL); for(int i=1;i<=n;i++) Set.insert(((2*a[i])%GCD+GCD)%GCD); while(m--) { long long q; scanf("%lld",&q); if(Set.find((q%GCD+GCD)%GCD)!=Set.end()) puts("Yes"); else puts("No"); } // fclose(stdin); // fclose(stdout); return 0; }