• 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
    ",ans);
    129     return 0;
    130 }
    View Code

    set也能写。不会。

  • 相关阅读:
    数组
    Java读取键盘输入
    Java不同类型字符转换String/int/Float/////
    微信公众号第三方验证的代码实现
    Debian Tips【在Debian下使用dos2unix、unix2dos、ifconfig、Adobe Flash Player、蓝牙音响等工具】
    数组的三种方式总结 多维数组的遍历 Arrays类的常用方法总结
    java基本数据类型总结 类型转换 final关键字的用法
    Maven通解
    IDEA——错误: 找不到或无法加载主类 com.Main
    Docker安装mysql,redis,mongodb数据库,docker常用命令,以及更换阿里镜像地址
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8075440.html
Copyright © 2020-2023  润新知