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 }

分块还差得远呢

posted @ 2018-03-14 16:36  F.W.Nietzsche  阅读(303)  评论(0编辑  收藏  举报