luogu P4108 [HEOI2015]公约数数列——solution
-by luogu
不会啊....
然后%了一发题解,
关键是
考虑序列{$a_n$}的前缀gcd序列,
它是单调不升的,且最多只会改变$log_2N$次,因为每变一次至少除2
于是,当我们询问x时:
对每一段满足前缀gcd不变的部分;
可以用map之类的直接查询这个区间中前缀xor值等于$x\over gcd$的最小下标;
但我们还有单点修改,
考虑分块,——随便分个根号块就好
对每块
维护块从左端到右端元素的xor和,
维护块中左端到右端元素的gcd值,
对每个元素
维护从他所在块的左端点到他自己的xor和与gcd值;
这样修改只影响一块之内的所有元素的相关值和这一块的相关值;
对每块开个map
把左端到每个元素的xor值插到对应块的map中去;
当我们查询x时
枚举每块,
如果到这块之前的前缀gcd等于加入这块之后的前缀gcd(设为gcd),则意味着这块之内(从左端到右端)的所有点的前缀gcd都相等,(前缀gcd单调不升)
这样的话,我们设到这块之前的xor为$XOR_{0,L-1}$我们只需在这块的map中查是否有某个$XOR_{l~i}$值满足$gcd*(XOR_{0,L-1}xorXOR_{l,i})=x$即可,其效率为map的效率,$O(log_2\sqrt{N})$乘上块数即为$O(\sqrt{N}log_2\sqrt{N})$
反之,则暴力枚举这块中的每个元素即可,这种情况不超过log次,其总效率为$O(\sqrt{N}log_2{N})$
至于修改,则直接把对这块所维护的信息重新维护即可即可,块大小为$\sqrt{N}$乘上map的效率为$O(\sqrt{N}log_2\sqrt{N})$
于是其总复杂度为$O(q\sqrt{N}log_2N)$
代码:
1 #include<map> 2 #include<cmath> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #define LL long long 8 using namespace std; 9 map <int ,int >MP[350]; 10 int a[100010]; 11 int b_size,b_num; 12 int L[350]; 13 int b_gcd[350],b_xor[350]; 14 int a_gcd[100010],a_xor[100010]; 15 int n,q; 16 char s[20]; 17 int GCD(int ,int ); 18 void modify(); 19 void query(); 20 int main() 21 { 22 int i,j,k; 23 scanf("%d",&n); 24 b_size=sqrt(n); 25 for(i=1;i<=n;i++) 26 scanf("%d",&a[i]); 27 for(b_num=i=1;i<=n;b_num++,i+=b_size){ 28 L[b_num]=i; 29 a_xor[i]=a_gcd[i]=a[i]; 30 MP[b_num].insert(pair<int ,int >(a_xor[i],i)); 31 for(j=i+1;j<i+b_size&&j<=n;j++){ 32 a_xor[j]=a_xor[j-1]^a[j]; 33 a_gcd[j]=GCD(a_gcd[j-1],a[j]); 34 MP[b_num].insert(pair<int ,int >(a_xor[j],j)); 35 } 36 b_xor[b_num]=a_xor[j-1],b_gcd[b_num]=a_gcd[j-1]; 37 } 38 scanf("%d",&q); 39 for(i=1;i<=q;i++){ 40 scanf("%s",s); 41 if(s[0]=='M') 42 modify(); 43 else 44 query(); 45 } 46 } 47 int GCD(int a,int b){ 48 if(!b)return a; 49 return GCD(b,a%b); 50 } 51 void modify(){ 52 int id,x,i,j,k; 53 scanf("%d%d",&id,&x),id++; 54 for(i=j=1;j<=n;j+=b_size,i++) 55 if(j+b_size>id) 56 break; 57 MP[i].clear(); 58 a[id]=x; 59 a_xor[(i-1)*b_size+1]=a_gcd[(i-1)*b_size+1]=a[(i-1)*b_size+1]; 60 MP[i].insert(pair<int ,int >(a_xor[(i-1)*b_size+1],(i-1)*b_size+1)); 61 for(j=(i-1)*b_size+2;j<=i*b_size&&j<=n;j++){ 62 a_xor[j]=a_xor[j-1]^a[j]; 63 a_gcd[j]=GCD(a_gcd[j-1],a[j]); 64 MP[i].insert(pair<int ,int >(a_xor[j],j)); 65 } 66 b_xor[i]=a_xor[j-1],b_gcd[i]=a_gcd[j-1]; 67 } 68 void query(){ 69 LL x,xx; 70 map <int ,int >::iterator iter; 71 int i,j,k,lasxor=0,nowgcd=0,lasgcd=0; 72 scanf("%lld",&x); 73 for(i=1;i<=b_num;i++){ 74 nowgcd=GCD(b_gcd[i],lasgcd); 75 if(nowgcd==lasgcd){ 76 if(x%lasgcd){ 77 lasgcd=nowgcd,lasxor^=b_xor[i]; 78 continue; 79 } 80 xx=x/lasgcd; 81 xx^=lasxor; 82 if(xx>0x7fffffff){ 83 lasgcd=nowgcd,lasxor^=b_xor[i]; 84 continue; 85 } 86 k=xx; 87 if(MP[i].count(k)==1){ 88 iter=MP[i].find(k); 89 printf("%d\n",iter->second-1); 90 return ; 91 } 92 } 93 else{ 94 for(j=(i-1)*b_size+1;j<=n&&j<=i*b_size;j++) 95 if(1ll*(lasxor^a_xor[j])*GCD(lasgcd,a_gcd[j])==x){ 96 printf("%d\n",j-1); 97 return ; 98 } 99 } 100 lasgcd=nowgcd,lasxor^=b_xor[i]; 101 } 102 printf("no\n"); 103 }
分块还差得远呢
Just close your eyes, you`ll be alright, no one can hurt you after you die.