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

先发掘性质:

1.xor和gcd均满足交换律与结合率。

2.前缀gcd最多只有O(log)个。

但并没有什么数据结构能同时利用这两个性质,结合Q=10000,考虑分块。

对每块记录这几个信息:

1.块内所有数的gcd与异或和。

2.将块内所有前缀异或和放入一个数组排序。

查询时从前往后遍历每个块:

1.若当前块不使gcd改变,二分查找是否存在答案。

2.若改变,暴力查找答案。

复杂度(设块大小为S,值域为M):

1.修改复杂度$O(S\log S)$

2.查询复杂度$O(S\log M+\frac{n}{S}\log S)$。

当$S=\sqrt{n}$时复杂度最优,为$O(Q\sqrt{n}\log n)$。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 typedef long long ll;
 5 using namespace std;
 6 
 7 const int N=100010,K=410;
 8 char op[10];
 9 int n,B,tot,Q,ans,L[K],R[K];
10 ll x,k,a[N],G[K],X[K];
11 struct P{ ll x; int id; }p[N];
12 bool operator <(const P &a,const P &b){ return (a.x==b.x) ? a.id<b.id : a.x<b.x; }
13 
14 ll gcd(ll a,ll b){ return b ? gcd(b,a%b) : a; }
15 
16 void build(int x){
17     G[x]=X[x]=a[L[x]]; p[L[x]]=(P){X[x],L[x]};
18     rep(j,L[x]+1,R[x]) G[x]=gcd(G[x],a[j]),X[x]^=a[j],p[j]=(P){X[x],j};
19     sort(p+L[x],p+R[x]+1);
20 }
21 
22 int find(int l,int r,ll k){
23     while (l<r){
24         int mid=(l+r)>>1;
25         if (p[mid].x<k) l=mid+1; else r=mid;
26     }
27     return r;
28 }
29 
30 int main(){
31     freopen("bzoj4028.in","r",stdin);
32     freopen("bzoj4028.out","w",stdout);
33     scanf("%d",&n); B=300; tot=(n-1)/B+1;
34     rep(i,1,n) scanf("%lld",&a[i]);
35     rep(i,1,tot) L[i]=(i-1)*B+1,R[i]=min(n,i*B),build(i);
36     for (scanf("%d",&Q); Q--; ){
37         scanf("%s",op);
38         if (op[0]=='M') scanf("%lld%lld",&x,&k),x++,a[x]=k,build((x-1)/B+1);
39         else{
40             scanf("%lld",&x); ll g=a[1],t=0; bool w=0;
41             rep(i,1,tot){
42                 if (gcd(g,G[i])==g){
43                     if (x%g==0){
44                         ll k=x/g^t; int ans=find(L[i],R[i],k);
45                         if (p[ans].x==(x/g^t)){ printf("%d\n",p[ans].id-1); w=1; break; }
46                     }
47                     g=gcd(g,G[i]); t^=X[i];
48                 }else
49                     rep(j,L[i],R[i]){
50                         g=gcd(g,a[j]); t^=a[j];
51                         if (g*t==x){ printf("%d\n",j-1); w=1; break; }
52                     }
53                 if (w) break;
54             }
55             if (!w) puts("no");
56         }
57     }
58     return 0;
59 }

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/9882234.html
今日推荐