CF671C. Ultimate Weirdness of an Array

n<=200000个<=200000的数问所有的f(i,j)的和,表示去掉区间i到j后的剩余的数字中任选两个数的最大gcd。

数论日常不会。。

先试着计算一个数组:Hi表示f(l,r)<=i的(l,r)的数量。这样答案就是i*(H_i - H_i-1)的和。要求删掉某个区间后剩余的区间的最大gcd,暴力一点,从大到小枚举gcd的值,然后对每个数记Next_i表示如果当前的gcd为<=x,以i节点做l,r能取到的最小值,那么一个gcd值x的H_x就是一个x对应的所有n-Next_i+1的和。

这样要n^2,问题在于没有考虑Next数组的特点。可以发现对每个x,Next数组是不递减的,而从大到小枚举x只会使限制越来越紧,然后使Next_i越来越大,如果能够在x变成x-1时做一些相应的修改就可以节省每次重算Next的时间。

假设一个x的所有倍数的下标是b1,b2,……,b_k,那么当x变成x-1后,[l,r]至少应覆盖k-1个数,所以i>b2时所有的i都要设成n+1表示对后面的H不再有贡献。b1<i<=b2时,至少要覆盖到bk,所以这些Next_i对bk取个Max,然后1<=i<=b1时,Next_i对b_(k-1)取个Max,完成一次修改。每次取H[x]只需要知道所有Next的和。

需要一个线段树。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 #include<math.h>
  6 #include<vector>
  7 //#include<iostream>
  8 using namespace std;
  9 
 10 int n;
 11 #define maxn 200011
 12 #define LL long long
 13 int a[maxn];
 14 vector<int> s[maxn];
 15 
 16 int prime[maxn],lp=0,xiao[maxn];bool notprime[maxn];
 17 void pre(int n)
 18 {
 19     for (int i=2;i<=n;i++)
 20     {
 21         if (!notprime[i]) prime[++lp]=i,xiao[i]=i;
 22         for (int j=1;j<=lp && 1ll*i*prime[j]<=n;j++)
 23         {
 24             xiao[i*prime[j]]=prime[j];
 25             notprime[i*prime[j]]=1;
 26             if (!(i%prime[j])) break;
 27         }
 28     }
 29 }
 30 
 31 int sep[maxn],lsep,numofsep[maxn];
 32 void dfs(int cur,int num,int idx)
 33 {
 34     if (cur>lsep) {s[num].push_back(idx);return;}
 35     dfs(cur+1,num,idx);
 36     for (int i=1,tmp=sep[cur];i<=numofsep[cur];i++,tmp*=sep[cur]) dfs(cur+1,num*tmp,idx);
 37 }
 38 
 39 struct SMT
 40 {
 41     struct Node
 42     {
 43         int ls,rs;
 44         LL sum,be,Max,Min;
 45     }a[maxn<<1];
 46     int size;
 47     SMT() {size=0;}
 48     void up(int x)
 49     {
 50         const int &p=a[x].ls,&q=a[x].rs;
 51         a[x].sum=a[p].sum+a[q].sum;
 52         a[x].Max=max(a[p].Max,a[q].Max);
 53         a[x].Min=min(a[p].Min,a[q].Min);
 54     }
 55     void build(int &x,int L,int R)
 56     {
 57         x=++size;
 58         if (L==R) {a[x].ls=a[x].rs=0; a[x].sum=a[x].Min=a[x].Max=L; a[x].be=0; return;}
 59         const int mid=(L+R)>>1;
 60         build(a[x].ls,L,mid); build(a[x].rs,mid+1,R); up(x);
 61     }
 62     void build() {int x;build(x,1,n);}
 63     int ql,qr; LL v;
 64     void modmaxsingle(int x,int L,int R,LL v)
 65     {
 66         a[x].sum=(R-L+1)*v;
 67         a[x].Max=a[x].Min=v;
 68         a[x].be=v;
 69     }
 70     void down(int x,int L,int R)
 71     {
 72         const int &p=a[x].ls,&q=a[x].rs,mid=(L+R)>>1;
 73         if (a[x].be) {modmaxsingle(p,L,mid,a[x].be); modmaxsingle(q,mid+1,R,a[x].be); a[x].be=0;}
 74     }
 75     void Modmax(int x,int L,int R)
 76     {
 77         if (a[x].Min>=v) return;
 78         if (ql<=L && R<=qr && a[x].Max<=v)
 79         {
 80             modmaxsingle(x,L,R,v);
 81             return;
 82         }
 83         down(x,L,R);
 84         const int mid=(L+R)>>1;
 85         if (ql<=mid) Modmax(a[x].ls,L,mid);
 86         if (qr> mid) Modmax(a[x].rs,mid+1,R);
 87         up(x);
 88     }    
 89     void modmax(int L,int R,LL v)
 90     {
 91         ql=L; qr=R; this->v=v;
 92         Modmax(1,1,n);
 93     }
 94 }t;
 95 
 96 LL h[maxn];
 97 int main()
 98 {
 99     scanf("%d",&n);
100     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
101     pre(200000);
102     for (int i=1;i<=n;i++)
103     {
104         int tmp=a[i];
105         lsep=0;
106         while (tmp>1)
107         {
108             if (sep[lsep]!=xiao[tmp]) sep[++lsep]=xiao[tmp],numofsep[lsep]=1;
109             else numofsep[lsep]++;
110             tmp/=xiao[tmp];
111         }
112         dfs(1,1,i);
113     }
114     t.build();
115     for (int g=200001;g;g--)
116     {
117         int size=s[g].size();
118         if (size>1)
119         {
120             t.modmax(s[g][1]+1,n,n+1);
121             t.modmax(s[g][0]+1,s[g][1],s[g][size-1]);
122             t.modmax(1,s[g][0],s[g][size-2]);
123         }
124         h[g]=1ll*n*(n+1)-t.a[1].sum;
125     }
126     LL ans=0;
127     for (int i=1;i<=200000;i++) ans+=i*(h[i+1]-h[i]);
128     printf("%lld\n",ans);
129     return 0;
130 }
View Code

set也能写。不会。

posted @ 2017-12-20 19:21  Blue233333  阅读(466)  评论(0编辑  收藏  举报