• 忍者钩爪 ( ninja) 题解———2019.10.19


    可以到这里测。。嘿嘿嘿

    题目:

    【问题 描述 】
    小 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%的分数

    可以使用暴力记忆化搜索得出答案。即维护每个坐标是否可达,继而进行搜索。

    对于60%的分数

    通过观察可知设当前坐标为x,则通过坐标为a的圆环可移动到2a-x处。连续通过两个圆环(a,b)可以移动到x+(2b-2a)处。

    先以移动步数为偶数情况考虑简化版问题:设圆环坐标为a[1]~a[n],对于任意两个圆环,可由坐标x变为x+2(a[j]-a[i]),题目转化为对于N^2个数其中b[i,j]=2(a[j]-a[i]),通过有限次加减运算能否由x=0变化至目标。

    根据广义裴蜀定理以及扩展欧几里得相关原理可知,当且仅当目标为gcd的倍数时有解。故预处理出全部可能的2(a[j]-a[i]),求出其最大公约数,在判断目标是否为gcd的倍数即可。

    对于奇数的情况,可以通过枚举第一步的方案转化为偶数的情况,即维护一个set表示0步或1步可达点集(mod gcd意义下),再查询目标点在mod gcd下是否属于这个集合即可。复杂度瓶颈在于N^2个数求gcd。

    对于100%的分数

    通过欧几里得算法的性质与更相减损术可知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
  • 相关阅读:
    Objective
    ios 贝塞尔画图
    M端的飞行宝石代码(启发性代码)
    T端单机定时间随机召唤生物的脚本
    T端升级宝石
    Xcode中如何屏蔽某个源文件的编译警告信息
    xcode合并模拟器和真机静态库的编译
    layoutSubviews setNeedsDisplay
    限制只能输入数字字母
    正确使用Block避免Cycle Retain和Crash
  • 原文地址:https://www.cnblogs.com/ydclyq/p/11705083.html
Copyright © 2020-2023  润新知