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 }
set也能写。不会。