BZOJ 4028 分块

zrt当年是怎么想到的…….
思路:
考虑把序列分块
对于每块 存xor[i] 表示从本块开头到i的前缀异或和
把它扔进set里
存gcd[i]表示从本块开头到i的前缀gcd.
如果这一块的GCD和整个的gcd的gcd是一样的 从set里找ans
否则暴力..
GCD最多log种 所以是复杂度是O(nsqrt(n)logn)的

//By SiriusRen
#include <cmath>
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100050;
int n,q,a[N],Block,block[N],XOR[N],GCD[N];
char op[150];
typedef long long ll;
set<int>s[320];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
signed main(){
    scanf("%d",&n),Block=sqrt(n);
    for(int i=0;i<n;i++)scanf("%d",&a[i]),block[i]=i/Block+1;
    for(int i=0;i<n;i++){
        if(block[i]==block[i-1])XOR[i]=XOR[i-1]^a[i],GCD[i]=gcd(a[i],GCD[i-1]);
        else XOR[i]=a[i],GCD[i]=a[i];
        s[block[i]].insert(XOR[i]);
    }
    scanf("%d",&q);
    while(q--){
        scanf("%s",op);
        if(op[0]=='M'){
            int xx,yy;
            scanf("%d%d",&xx,&yy),a[xx]=yy;
            s[block[xx]].clear();
            int tp=lower_bound(block,block+n,block[xx])-block;
            XOR[tp]=a[tp],GCD[tp]=a[tp];s[block[xx]].insert(XOR[tp]);
            for(int i=tp+1;block[i]==block[tp];i++)
                XOR[i]=XOR[i-1]^a[i],GCD[i]=gcd(a[i],GCD[i-1]),s[block[xx]].insert(XOR[i]);
        }
        else{
            ll Q;int Gcd=GCD[lower_bound(block,block+n,2)-block-1],Xor=XOR[lower_bound(block,block+n,2)-block-1];
            scanf("%lld",&Q);
            for(int i=0;block[i]==1;i++)
                if((ll)GCD[i]*XOR[i]==Q){printf("%d\n",i);goto ed;}
            for(int i=2;i<=block[n-1];i++){
                if(gcd(GCD[upper_bound(block,block+n,i)-block-1],Gcd)!=Gcd){
                    int tp=lower_bound(block,block+n,i)-block;
                    for(int j=tp;block[j]==block[tp];j++){
                        Gcd=gcd(Gcd,a[j]),Xor^=a[j];
                        if((ll)Gcd*Xor==Q){printf("%d\n",j);goto ed;}
                    }
                    continue;
                }
                ll temp=(Q/Gcd)^Xor;
                if(s[i].find(temp)!=s[i].end()){
                    int tp=lower_bound(block,block+n,i)-block;
                    for(int j=tp;block[j]==block[tp];j++)
                        if(XOR[j]==temp){printf("%d\n",j);goto ed;}
                }
                Xor^=XOR[upper_bound(block,block+n,i)-block-1];
            }
            puts("no");
        }ed:;
    }
}

转载于:https://www.cnblogs.com/SiriusRen/p/6532023.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值