首页 > 代码库 > bzoj 4028 : [HEOI2015]公约数数列

bzoj 4028 : [HEOI2015]公约数数列

之前看了好几次都没什么思路,今天下定决心把这题切了。

观察到$0-x$的gcd最多变化log次,因为它每次变化一定至少要去掉一个质因子,所以我们可以枚举gcd。

因为数据范围比较小,所以想到了分块。

设T为块的大小。

维护块首到块里每个位置的gcd和xor,再把xor排序。

修改的时候暴力改就行,复杂度$TlogT$。

询问的时候如果gcd在这个块里变化了,就把这个块暴力扫一遍,否则说明gcd在这个块里不变,相当于在区间里查是否有某个特定的值,随便二分一下,复杂度$T log inf+\frac{n}{T}logT$。

  1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<algorithm>  5 #include<vector>  6 #define N 100005  7 #define d 200  8 #define ll long long  9 using namespace std; 10 const int inf = 2000000000; 11 int gcd(int a,int b) 12 { 13     if(!b)return a; 14     return gcd(b,a%b); 15 } 16 int n; 17 int a[N]; 18 int gd[N],xr[N],be[N]; 19 vector<int>g[N]; 20 vector<int>::iterator it; 21 bool cmp(int x,int y) 22 { 23     if(xr[x]==xr[y])return x<y; 24     return xr[x]<xr[y]; 25 } 26 void gai(int x,int y) 27 { 28     int k=be[x];a[x]=y; 29     int l=(k-1)*d+1,r=min(k*d,n); 30     int xx=0,now=a[l];g[k].clear(); 31     for(int i=l;i<=r;i++) 32     { 33         now=gcd(now,a[i]); 34         xx=xx^a[i]; 35         gd[i]=now; 36         xr[i]=xx; 37         g[k].push_back(i); 38     } 39     sort(g[k].begin(),g[k].end(),cmp); 40 } 41 void solve(ll x) 42 { 43     int now=a[1];int cnt=0,ed,xx=0; 44     for(int i=1;i<=n;i+=d) 45     { 46         cnt++;ed=min(n,i+d-1); 47         if(gd[ed]%now!=0) 48         { 49             for(int j=i;j<=ed;j++) 50             { 51                 if(gd[j]%now!=0)now=gcd(now,gd[j]); 52                 if(x%now==0&&x/now==(ll)(xx^xr[j])) 53                 { 54                     printf("%d\n",j-1); 55                     return ; 56                 } 57             } 58         } 59         else 60         { 61             if(x%now==0&&x/now<=inf) 62             { 63                 int tmp=x/now; 64                 int l=0,r=g[cnt].size()-1; 65                 tmp^=xx; 66                 if(xr[g[cnt][r]]<tmp) 67                 { 68                     xx^=xr[ed]; 69                     continue; 70                 } 71                 while(l<r) 72                 { 73                     int mid=(l+r)>>1; 74                     if(xr[g[cnt][mid]]>=tmp)r=mid; 75                     else l=mid+1; 76                 } 77                 if(xr[g[cnt][r]]==tmp) 78                 { 79                     printf("%d\n",g[cnt][r]-1); 80                     return ; 81                 } 82             } 83         } 84         xx^=xr[ed]; 85     } 86     puts("no"); 87     return ; 88 } 89 int main() 90 { 91     scanf("%d",&n); 92     for(int i=1;i<=n;i++)scanf("%d",&a[i]); 93     int cnt=0; 94     for(int i=1;i<=n;i+=d) 95     { 96         cnt++; 97         int ed=min(n,i+d-1); 98         int now=a[i];int xx=0; 99         for(int j=i;j<=ed;j++)100         {101             be[j]=cnt;102             now=gcd(now,a[j]);103             xx=xx^a[j];104             gd[j]=now;105             xr[j]=xx;106             g[cnt].push_back(j);107         }108         sort(g[cnt].begin(),g[cnt].end(),cmp);109     }110     int m;scanf("%d",&m);111     char s[10];112     int t1,t2;ll t3;113     for(int i=1;i<=m;i++)114     {115         scanf("%s",s);116         if(s[0]==M)117         {118             scanf("%d%d",&t1,&t2);119             t1++;gai(t1,t2);120         }121         else122         {123             scanf("%lld",&t3);124             solve(t3);125         }126     }127     return 0;128 }

 

bzoj 4028 : [HEOI2015]公约数数列