codeforces 671C
2017-01-28 23:32
323 查看
题意定义f(l,r)为去掉[l,r]部分后剩下的数任意两个数的最大公约数的最大值
现在求f(l,r)的和
由于每个数ai最大只有200000,因此我们穷举因子x,记录以其为因子的a[i]的i值并按i升序。
下面我们从大到小穷举每个因子x,我们依次计算以f(l,r)=x的区间数,
有了上述的维护信息,我们很容易三种情况的区间满足f(l,r)=x(我就不具体细说了)
令pre[i]表示当前以第i个位置结尾的区间满足任意j(1<=j<=pre[i]),f(j,i)<x
显然f(l,r)=x的区间数=当前还没计算过的区间数-∑pre[i]
这就要维护∑pre[i],每次修改是将一段区间pre[i]>x的数赋值为x
显然pre[i]是单调不上升,因此可以用线段树维护之
View Code
现在求f(l,r)的和
由于每个数ai最大只有200000,因此我们穷举因子x,记录以其为因子的a[i]的i值并按i升序。
下面我们从大到小穷举每个因子x,我们依次计算以f(l,r)=x的区间数,
有了上述的维护信息,我们很容易三种情况的区间满足f(l,r)=x(我就不具体细说了)
令pre[i]表示当前以第i个位置结尾的区间满足任意j(1<=j<=pre[i]),f(j,i)<x
显然f(l,r)=x的区间数=当前还没计算过的区间数-∑pre[i]
这就要维护∑pre[i],每次修改是将一段区间pre[i]>x的数赋值为x
显然pre[i]是单调不上升,因此可以用线段树维护之
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 int laz[200010*4],mi[200010*4],mx[200010*4]; 6 ll tr[200010*4]; 7 vector<int> g[200010]; 8 int n,m; 9 void build(int i,int l,int r) 10 { 11 laz[i]=-1; 12 if (l==r) mx[i]=mi[i]=tr[i]=l; 13 else { 14 int m=(l+r)>>1; 15 build(i*2,l,m); 16 build(i*2+1,m+1,r); 17 tr[i]=tr[i*2]+tr[i*2+1]; 18 mx[i]=max(mx[i*2],mx[i*2+1]); 19 mi[i]=min(mi[i*2],mi[i*2+1]); 20 } 21 } 22 23 void work(int i,int l,int r,int x,int y,int z) 24 { 25 // if (i==1) cout <<z<<endl; 26 if (x>y) return; 27 if (mx[i]<=z) return; 28 if (x<=l&&y>=r&&mi[i]>z) 29 { 30 mi[i]=mx[i]=laz[i]=z; 31 tr[i]=(ll)(r-l+1)*z; 32 } 33 else { 34 int m=(l+r)>>1; 35 if (laz[i]>-1) 36 { 37 laz[i*2]=laz[i*2+1]=laz[i]; 38 mi[i*2]=mx[i*2]=laz[i]; 39 mi[i*2+1]=mx[i*2+1]=laz[i]; 40 tr[i*2]=(ll)laz[i]*(m-l+1); 41 tr[i*2+1]=(ll)laz[i]*(r-m); 42 laz[i]=-1; 43 } 44 if (x<=m) work(i*2,l,m,x,y,z); 45 if (y>m) work(i*2+1,m+1,r,x,y,z); 46 tr[i]=tr[i*2]+tr[i*2+1]; 47 mx[i]=max(mx[i*2],mx[i*2+1]); 48 mi[i]=min(mi[i*2],mi[i*2+1]); 49 } 50 } 51 52 int main() 53 { 54 scanf("%d",&n); 55 for (int i=1; i<=n; i++) 56 { 57 int x;scanf("%d",&x); 58 for (int j=1; j*j<=x; j++) 59 if (x%j==0) 60 { 61 g[x/j].push_back(i); 62 if (j*j!=x) g[j].push_back(i); 63 } 64 m=max(m,x); 65 } 66 build(1,1,n); 67 ll pre=(ll)n*(n+1)/2; 68 ll ans=0; 69 for (int i=m; i; i--) 70 { 71 if (g[i].size()<2) continue; 72 int j=g[i].size()-1; 73 work(1,1,n,g[i][0]+1,g[i][j]-1,g[i][0]); 74 work(1,1,n,1,g[i][j-1]-1,0); 75 work(1,1,n,g[i][1]+1,n,g[i][1]); 76 ans+=(pre-tr[1])*(ll)i; 77 // cout <<tr[1]<<endl; 78 pre=tr[1]; 79 } 80 printf("%lld\n",ans); 81 }
View Code
相关文章推荐
- VTK修炼之道37:图像平滑_高斯滤波器
- java中的注解以及简单了解ButterKnife原理
- HDU - 5384 Danganronpa AC自动机、简单题
- 把Dos文件转成Linux文件
- RedisRepository分享和纠错_0
- BZOJ 3585: mex [主席树]
- Git - Tips
- favico.js笔记
- RedisRepository分享和纠错
- java正则表达式验证金额
- gulp开发简单配置以及配合browserify应用
- Servlet之ServletContext获取web上下文路径、全局参数、和Attribute(域)
- 理解矩阵乘法
- 好奇号火星车旅行日志January 25, 2017 – Wednesday火星日1591-1592车轮检查
- Recurrent Neural Network系列3--理解RNN的BPTT算法和梯度消失_0
- Git - 分支
- VTK修炼之道36:图像平滑_均值滤波器
- ssh localhost免密码后依然需要输入密码问题的解决
- Recurrent Neural Network系列3--理解RNN的BPTT算法和梯度消失
- spring---整合Junit,整合web