zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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 }
  • 相关阅读:
    python_day06(ip代理池)
    二叉树的层次遍历之队列的使用
    推荐系统实战笔记 1.1什么是推荐系统
    牛顿法求平方根可拓展
    java LinkedHashMap实现LRUCache缓存
    交换两个变量常规四种做法
    交换两个变量之移位交换法
    推荐系统实战笔记01--前言
    Ubuntu 14.04更新为国内阿里源解决apt-get install无法执行的问题
    求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6596160.html
Copyright © 2011-2022 走看看