bzoj 4028 : [HEOI2015]公约数数列
Posted SD_le
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 else 122 { 123 scanf("%lld",&t3); 124 solve(t3); 125 } 126 } 127 return 0; 128 }
以上是关于bzoj 4028 : [HEOI2015]公约数数列的主要内容,如果未能解决你的问题,请参考以下文章