忍者鉤爪 ( ninja) 題解———2019.10.19

能夠到這裏測。。嘿嘿嘿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;
}
View Code
相關文章
相關標籤/搜索