luogu P4108 [HEOI2015]公約數數列——solution

 

 -by luoguspa



不會啊....code

而後%了一發題解,blog

關鍵是string

考慮序列{$a_n$}的前綴gcd序列,it

它是單調不升的,且最多隻會改變$log_2N$次,由於每變一次至少除2io

因而,當咱們詢問x時:class

對每一段知足前綴gcd不變的部分;效率

能夠用map之類的直接查詢這個區間中前綴xor值等於$x\over gcd$的最小下標;map

但咱們還有單點修改,gc

考慮分塊,——隨便分個根號塊就好

對每塊

維護塊從左端到右端元素的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 }

分塊還差得遠呢

相關文章
相關標籤/搜索