【BZOJ4028】[HEOI2015]公约数数列(分块)

【BZOJ4028】[HEOI2015]公约数数列(分块)

题面

BZOJ
洛谷

题解

看一道题目就不会做系列
首先\(gcd\)最多只会有\(log\)种取值,所以我们可以暴力枚举出所有可能的\(gcd\)
那么我们现在按照步骤要解决两个问题。第一个是怎么动态维护\(gcd\)的取值,第二个是怎么动态维护异或和。
我们考虑分块。
只维护块内的前缀\(gcd\)和前缀异或和,这样子每次修改只需要暴力重构块。
每次询问的时候如果块内的\(gcd\)不变,那么二分答案,找找有没有满足条件的异或和。
否则直接暴力扫这一块。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
const int blk=400;
int L[blk],R[blk];
int g[MAX],s[MAX],a[MAX];
struct Data{int id,v;}b[MAX];
bool operator<(Data a,Data b){if(a.v!=b.v)return a.v<b.v;return a.id<b.id;}
void Build(int p)
{
    g[L[p]]=s[L[p]]=a[L[p]];
    for(int i=L[p]+1;i<=R[p];++i)
    {
        g[i]=__gcd(g[i-1],a[i]);
        s[i]=s[i-1]^a[i];
    }
    for(int i=L[p];i<=R[p];++i)b[i]=(Data){i,s[i]};
    sort(&b[L[p]],&b[R[p]+1]);
}
int n,bel[MAX];
char ch[10];
int main()
{
    n=read();
    for(int i=1;i<=n;++i)bel[i]=(i-1)/blk+1;
    for(int i=1;i<=n;++i)if(!L[bel[i]])L[bel[i]]=i;
    for(int i=1;i<=n;++i)R[bel[i]]=i;
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=bel[n];++i)Build(i);
    int Q=read();
    while(Q--)
    {
        scanf("%s",ch);
        if(ch[0]=='M')
        {
            int x=read()+1,y=read();
            a[x]=y;Build(bel[x]);
        }
        else
        {
            ll x;scanf("%lld",&x);
            int D=a[1],ans=-1,X=0;
            for(int i=1;i<=bel[n]&&ans==-1;++i)
                if(__gcd(D,g[R[i]])==D)
                {
                    if(x%D==0)
                    {
                        ll k=(x/D)^X;
                        int l=L[i],r=R[i],ret=l;
                        while(l<=r)
                        {
                            int mid=(l+r)>>1;
                            if(b[mid].v>=k)ret=mid,r=mid-1;
                            else l=mid+1;
                        }
                        if(b[ret].v==k){ans=b[ret].id;break;}
                    }
                    D=__gcd(D,g[R[i]]);X^=s[R[i]];
                }
                else
                    for(int j=L[i];j<=R[i];++j)
                    {
                        D=__gcd(D,a[j]);X^=a[j];
                        if(1ll*D*X==x){ans=j;break;}
                    }
            if(!~ans)puts("no");
            else printf("%d\n",ans-1);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjyyb/p/10771584.html
今日推荐