牛客练习赛 66

A.平方数

讨论一下最接近它的两个平方数即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        ll x;
        cin>>x;
        ll y=sqrt(x);
        ll z=y+1;
        z*=z;
        y*=y;
        if(abs(y-x)<abs(z-x)) cout<<y<<'\n';
        else cout<<z<<'\n';
    }
    return 0;
}

B.异或图

首先我们要知道一个性质 x ⊕ x = 0 x\oplus x=0 xx=0
设起点为 s s s,终点为 t t t,如果存在一条路径 s − > p 1 − > p 2 − > p i − > e s->p_1->p_2->p_i->e s>p1>p2>pi>e那么说明有以下等式 a [ s ] ⊕ a [ p 1 ] = k a [ p 1 ] ⊕ a [ p 2 ] = k a [ p 2 ] ⊕ a [ p i ] = k a [ p i ] ⊕ a [ t ] = k a[s]\oplus a[p_1]=k \\ a[p_1]\oplus a[p_2]=k \\a[p_2]\oplus a[p_i]=k\\ a[p_i]\oplus a[t]=k a[s]a[p1]=ka[p1]a[p2]=ka[p2]a[pi]=ka[pi]a[t]=k我们不难发现如果有一条路径能够使得 s − > ⋯ − > t s->\dots->t s>>t说明 a [ s ] ⊕ a [ e ] = 0 / k a[s] \oplus a[e]=0/k a[s]a[e]=0/k,并且明显如果 a [ s ] ⊕ a [ e ] = k a[s] \oplus a[e]=k a[s]a[e]=k答案是 1 1 1,如果 a [ s ] ⊕ a [ e ] = 0 a[s] \oplus a[e]=0 a[s]a[e]=0需要判断是否有中间点即 a [ e ] ⊕ k a[e]\oplus k a[e]k是否存在即可,如存在答案是 2 2 2,否则不存在路径答案是 − 1 -1 1
刚开始以为 2 20 2^{20} 220很大数组开不下,用unordered_map存的个数,结果一直T,最后发现数组能开下直接就A了。~。·

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1100010;
int a[N],cnt[N];
int n,q;
int main()
{
    
    
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d",&a[i]);
        cnt[a[i]]++;
    }
    while(q--)
    {
    
    
        int k,st,ed;
        scanf("%d%d%d",&k,&st,&ed);
        if((a[st]^a[ed])==k) printf("1\n");
        else
        {
    
    
            int x=a[st]^k,y=a[ed]^k;
            if(x!=y||!cnt[x]) printf("-1\n");
            else printf("2\n");
        }
    }
    return 0;
}

C.公因子

辗转相除法扩展可得以下式子,然后不难乱搞求解
g c d ( a 1 , a 2 , a 3 , … , a n ) = g c d ( a 1 , a 2 − a 1 , a 3 − a 2 , … , a n − a n − 1 ) gcd(a_1,a_2,a_3,\dots,a_n)=gcd(a_1,a_2-a_1,a_3-a_2,\dots,a_n-a_{n-1}) gcd(a1,a2,a3,,an)=gcd(a1,a2a1,a3a2,,anan1)

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1100010;
ll a[N];
int n;
ll gcd(ll a,ll b)
{
    
    
    return b?gcd(b,a%b):a;
}
int main()
{
    
    
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
      cin>>n;
      for(int i=1;i<=n;i++) cin>>a[i];
      sort(a+1,a+1+n);
      ll d=a[2]-a[1];
      for(int i=3;i<=n;i++) d=gcd(d,a[i]-a[i-1]);
      if(d<0) d=-d;
      ll res=abs(a[1]/d*d-a[1]);
      cout<<d<<' '<<res<<'\n';
    }
    return 0;
}

E.骚区间

参考大佬题解
一般这种区间左右端点都不确定的情况,我们尝试固定一段点,求另一个端点的可行范围。
对于i位置作为左端点,考虑如何求右端点的合法区间,由于a[i]是第二小值,在[i+1,n]范围内第一个小于a[i]的位置是l1,在[i+1,n]范围内第二个小于a[i]的位置是r1,不难看出对于[l1,r1)范围满足左区间限制条件。
对于i位置作为右端点,我们同样可以如法炮制的求出满足右端点限制条件的区间(l2,r2]
我们可以维护一个树状数组差分求得答案。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
int a[N],n;
struct node
{
    
    
    int l,r;
    int mx,mn;
}tree[N*4];
void pushup(int u)
{
    
    
    tree[u].mx=max(tree[u<<1].mx,tree[u<<1|1].mx);
    tree[u].mn=min(tree[u<<1].mn,tree[u<<1|1].mn);
}
void build(int u,int l,int r)
{
    
    
    tree[u]={
    
    l,r,0,n+1};
    if(l==r)
    {
    
    
        tree[u].mx=tree[u].mn=a[l];
        return;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}
int query_min(int u,int l,int r,int x)
{
    
    
    if(l>r) return n+1;
    if(tree[u].mn>=x) return n+1;
    if(tree[u].l==tree[u].r) return tree[u].l;
    int mid=tree[u].l+tree[u].r>>1;
    
    if(l>mid) return query_min(u<<1|1,l,r,x);
    else if(r<=mid) return query_min(u<<1,l,r,x);
    else
    {
    
    
        if(tree[u<<1].mn<x)
        {
    
    
            int v=query_min(u<<1,l,r,x);
            return v!=n+1?v:query_min(u<<1|1,l,r,x);
        }
        else
            return query_min(u<<1|1,l,r,x);
    }
}
int query_max(int u,int l,int r,int x)
{
    
    
    if(l>r) return 0;
    if(tree[u].mx<=x) return 0;
    if(tree[u].l==tree[u].r) return tree[u].l;
    int mid=tree[u].l+tree[u].r>>1;
    
    if(l>mid) return query_max(u<<1|1,l,r,x);
    else if(r<=mid) return query_max(u<<1,l,r,x);
    else
    {
    
    
        if(tree[u<<1|1].mx>x) 
        {
    
    
            int v=query_max(u<<1|1,l,r,x);
            return v?v:query_max(u<<1,l,r,x);
        }
        else 
            return query_max(u<<1,l,r,x);
    }
}
vector<int> p[N];
int cnt[N];
int lowbit(int x)
{
    
    
    return x&-x;
}
void update(int k,int x)
{
    
    
    for(;k<=n;k+=lowbit(k)) cnt[k]+=x;
}
ll query(int k)
{
    
    
    ll now=0;
    for(;k;k-=lowbit(k)) now+=cnt[k];
    return now;
}
int main()
{
    
    
    
    int T=1;
    //cin>>T;
    while(T--)
    {
    
    
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        ll res=0;
        for(int i=1;i<=n;i++)
        {
    
    
            
            int l=query_min(1,i+1,n,a[i]);
            int r=query_min(1,l+1,n,a[i]);
            if(l!=n+1) p[l].push_back(i);
            if(r!=n+1) p[r].push_back(-i);
            for(auto t:p[i])
            {
    
    
                if(t>0) update(t,1);
                else update(-t,-1);
            }
            r=query_max(1,1,i-1,a[i]);
            l=query_max(1,1,r-1,a[i]);
            res+=query(r)-query(l);
        }
        printf("%lld\n",res);
    }
    return 0;
}

要加油哦~

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/108651793