牛客练习赛66题解

比赛地址
A.平方数
思路:暴力打表

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;

typedef long long ll;

const int N=1e6+10;
ll a[N];

void get_sqrt(int n)
{
    for(ll i=1;i<=n;i++)a[i]=i*i;
}

int main()
{
    ll x,y=0;
    scanf("%lld",&x);
    get_sqrt(1e6+3);
    for(int i=1;i<=x;i++){
        if(abs(y-x)>abs(a[i]-x))y=a[i];
        else break;
    }
    printf("%lld\n",y);
    return 0;
}

B 异或图
思路:每次输入k,x,y时异或一下x和y节点对应的点权,判断是否与k相等,相等则直接输出-1,否则继续判断,看这个图中是否存在中介点使得x和y节点可以互相到达,即利用异或性质判断k^x以后所得的结果是否在点集中,在则输出2,否则输出-1,不存在比2更大的距离,因为假如x和y中间存在多于一个点,比如2个点时,x和点1异或后等于k,点1和点2异或等于k,则点2等于x,其实就是x点,因此,不可能存在大于2的距离,由此只需判断当a[x]==a[y]时用k异或x或者y对应的点权后所得结果是否在这个点集图中,在则存在中介点连接x和y节点,距离为2,否则输出-1

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

typedef long long ll;
const int N=2*1e6;
int a[N];
bool vis[N];//因为2的20次方是1,048,576

int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);vis[a[i]]=true;}
    while(q--){
        int k,x,y;
        scanf("%d%d%d",&k,&x,&y);
        x=a[x],y=a[y];
        if((x^y)==k)puts("1");
        else if(x==y&&vis[k^x]==true)puts("2");
        else puts("-1");
    }
    return 0;
}

C 公因子
思路:gcd性质的应用
分析:要求a数组同时+x后的gcd,我们先来观察一下数据范围,n<=1e6,数组开到1e6+10足够了,而a的元素范围在正负10的18次方范围内,因此肯定要开longlong,再来观察一下式子的特点,我们发现+x后元素本身大小虽然变了,但是元素之间的差值不变,即ai->ai+x,aj->aj+x,但是(aj+x)-(ai+x)=aj-ai,由此联想到gcd的一条性质gcd(a,b)=gcd(a,b-a),因此,求+x后的a数组的gcd就可以转化成求原数组的差分数组的gcd,这样就不必苦恼没有x不好动手,求出gcd后因为a1+x必然是gcd的倍数,因此直接构造满足条件的x,当x<0时直接构造x=abs(a[1])使得a1+x后变成0,仍然满足a1+x整除gcd,而a1>0时由于数组gcd是通过差值求出来的,即ai-a1要能整除gcd,因此令x=gcd-a1,使得a1+x=a1+gcd-a1–>ai+x=ai+gcd-a1,显然可以使得ai+x整除gcd成立,因此构造成立((ai-a1)%gcd=0,因为gcd就是通过这么得到的,所以这个式子肯定成立,又gcd%gcd==0,所以ai+gcd-a1必然能整除gcd,所以构造成立)(这里构造的差分数组可以构造ai+1-ai这种,也可以ai-a1,固定一个a1作为定点来计算差值,都是可以ac的
ac:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

typedef long long ll;
const int N=1e6+10;
ll a[N];

ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}

int main()
{
    int n;
    scanf("%d",&n);
    ll d=0,x;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(int i=2;i<=n;i++){
        d=gcd(d,a[i]-a[1]);//也可以a[i]-a[i-1]
    }
    if(a[1]<0)x=abs(a[1])%d;
    else x=(d-a[1]%d);
    printf("%lld %lld\n",d,x);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值