看见$a_i\leq 200000$和gcd,就大概知道是要枚举gcd也就是答案了...

  因为答案是max,可以发现我们很容易算出<=i的答案,但是很难求出单个i的答案,所以我们可以运用差分的思想。

  $H[i]$表示$f(l,r)<=i$的$(l,r)$对数,显然这个是随i增大而单调不降的,考虑怎么计算出这个。

  $next[l]$表示满足$f(l,r)<=i$的最小的$r$,则有$H[i]=\sum_{l=1}^{n}n-next[l]+1$。显然$next[l]$也会随着$i$变小而单调不降,并且$next$数组本身也是单调不降的,于是我们可以从大到小枚举$i$。$i=max(a[i])$的时候显然有$next[i]=i$,接下来只要考虑每次从$i$变成$i-1$的时候$next$数组怎么变化。

  用一个vector $v[i]$来存下约数里有$i$的数的下标,并且单调递增。设$v[i]$里有下标$x_1,x_2,x_3,...,x_m$,则从$i$变为$i-1$的时候,任何一个$[l,r]$至少包含$m-1$个$x_j$,所以$[x_2+1,n]$这段区间的$next[l]$应该全改为$n+1$,$[x_1+1,x_2]$这段区间的$next[l]$应该改为$max(next[l],x_m)$,$[1,x_1]$这段区间的$next[l]$应该改为$max(next[l],x_{m-1})$,这个可以用线段树来实现。

  怎么实现呢?刚才我们提到过$next[l]$单调不降,有了这个性质就很好实现了。

  每个节点维护$mn$和$mx$表示这个区间里的最小的$next$和最大的$next$,如果$mn \geq delta$,那就不用再递归这个区间了,如果$mx<delta$,那么直接给这个区间打标记,这么做就能找到需要改的区间了。

  然后求出$H[i]$就完了...

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=;
struct poi{int mx, mn, delta; ll sum;}tree[maxn<<];
int n, a[maxn], pos[maxn], mx;
ll ans, H[maxn];
vector<int>v[maxn];
inline void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-' && (f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
inline void change(int x, int l, int r, int delta)
{
tree[x].mn=tree[x].mx=delta;
tree[x].sum=1ll*(r-l+)*delta;
tree[x].delta=delta;
}
inline void up(int x)
{
tree[x].mn=min(tree[x<<].mn, tree[x<<|].mn);
tree[x].mx=max(tree[x<<].mx, tree[x<<|].mx);
tree[x].sum=tree[x<<].sum+tree[x<<|].sum;
}
inline void down(int x, int l, int r)
{
if(!tree[x].delta) return;
int mid=(l+r)>>;
change(x<<, l, mid, tree[x].delta);
change(x<<|, mid+, r, tree[x].delta);
tree[x].delta=;
}
void build(int x, int l, int r)
{
if(l==r) {tree[x].mn=tree[x].mx=tree[x].sum=l; return;}
int mid=(l+r)>>;
build(x<<, l, mid); build(x<<|, mid+, r);
up(x);
}
void update(int x, int l, int r, int cl, int cr, int delta)
{
if(tree[x].mn>=delta) return;
down(x, l, r);
if(cl<=l && r<=cr && tree[x].mx<delta) {change(x, l, r, delta); return;}
int mid=(l+r)>>;
if(cl<=mid) update(x<<, l, mid, cl, cr, delta);
if(cr>mid) update(x<<|, mid+, r, cl, cr, delta);
up(x);
}
int main()
{
read(n);
for(int i=;i<=n;i++) read(a[i]), pos[a[i]]=i, mx=max(mx, a[i]);
for(int i=;i<=mx;i++)
{
for(int j=i;j<=mx;j+=i)
if(pos[j]) v[i].push_back(pos[j]);
sort(v[i].begin(), v[i].end());
}
build(, , n);
for(int i=mx;~i;i--)
{
H[i]=1ll*n*n-tree[].sum+n;
int m=v[i].size();
if(m<=) continue;
update(, , n, v[i][]+, n, n+);
update(, , n, v[i][]+, v[i][], v[i][m-]);
update(, , n, , v[i][], v[i][m-]);
}
for(int i=;i<=mx;i++) ans+=1ll*i*(H[i]-H[i-]);
printf("%I64d\n", ans);
}

Codeforces 671C. Ultimate Weirdness of an Array(数论+线段树)的更多相关文章

  1. Codeforces 671C - Ultimate Weirdness of an Array(线段树维护+找性质)

    Codeforces 题目传送门 & 洛谷题目传送门 *2800 的 DS,不过还是被我自己想出来了 u1s1 这个 D1C 比某些 D1D 不知道难到什么地方去了 首先碰到这类问题我们肯定考 ...

  2. codeforces 671C Ultimate Weirdness of an Array 线段树+构造

    题解上说的很清楚了,我照着写的,表示膜拜题解 然后时间复杂度我觉得应该是O(nlogn),虽然常数略大,预处理和倒着扫,都是O(nlogn) #include <stdio.h> #inc ...

  3. CodeForces 671C - Ultimate Weirdness of an Array

    题意: 给以一个定义, F(l, r) 的值表示序列 A[1:n]的子序列 A[1....(l-1),(r+1)...n] 之中 任意两个数的最大公约数的最大值. 求 Sum=∑i=1N∑j=1N(F ...

  4. CodeForces Round #179 (295A) - Greg and Array 一个线段树做两次用

    线段树的区间更新与区间求和...一颗这样的线段树用两次... 先扫描1~k...用线段树统计出每个操作执行的次数... 那么每个操作就变成了 op. l  , op.r , op.c= times* ...

  5. 【CodeForces】671 C. Ultimate Weirdness of an Array

    [题目]C. Ultimate Weirdness of an Array [题意]给定长度为n的正整数序列,定义一个序列的价值为max(gcd(ai,aj)),1<=i<j<=n, ...

  6. [Codeforces 464E] The Classic Problem(可持久化线段树)

    [Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...

  7. CF671C. Ultimate Weirdness of an Array

    n<=200000个<=200000的数问所有的f(i,j)的和,表示去掉区间i到j后的剩余的数字中任选两个数的最大gcd. 数论日常不会.. 先试着计算一个数组:Hi表示f(l,r)&l ...

  8. codeforces 482B. Interesting Array【线段树区间更新】

    题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val. 就是区间l---r上的与的值为val,最后问你原来的数 ...

  9. codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)

    In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...

随机推荐

  1. MySQL☞左外链接与右外连接

    外链接查询:即要查询有关联关系的数据,还要查询没有关联关系的数据.(个人理解为:表A和表B两个关联的列中)如下图: emmm,简单的来说两个表的关联关系:book.bid=bookshop.id,他们 ...

  2. openstack系列文章(三)

    学习openstack的系列文章-glance glance 基本概念 glance 架构 openstack CLI Troubleshooting 1. glance 基本概念 在 opensta ...

  3. 洛谷【P1854】花店橱窗布置

    https://www.luogu.org/problemnew/show/P1854 题目描述 某花店现有编号由 1 到 F 的 F 束花, 每一束花的品种都不一样. 编号由 1 到 V 的 V 个 ...

  4. Qt 编程指南

    Qt 编程指南 持续关注一本正在编写的Qt编程指南,期待作者早日完成创作.

  5. eFPGA与FPGA SoC,谁将引领下一代可编程硬件之潮流?|半导体行业观察

    eFPGA:冉冉升起的新星 eFPGA即嵌入式FPGA(embedded FPGA),是近期兴起的新型电路IP. 随着摩尔定律越来越接近瓶颈,制造ASIC芯片的成本越来越高.因此,设计者会希望ASIC ...

  6. redis memcache 比较

    Redis与Memcached的区别 传统MySQL+ Memcached架构遇到的问题 实际MySQL是适合进行海量数据存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都 ...

  7. 直接抱过来dd大牛的《背包九讲》来做笔记

    P01: 01背包问题 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 基本思路 这是最 ...

  8. Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 03

    此次作业要求参见https://edu.cnblogs.com/campus/nenu/2018fall/homework/2286 Scrum master:范洪达 一.小组介绍 组长:王一可 组员 ...

  9. HDU 5636 Shortest Path

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 题解: 1.暴力枚举: #include<cmath> #include<c ...

  10. Alpha 冲刺9

    队名:日不落战队 安琪(队长) 今天完成的任务 协助开发手写涂鸦demo. okhttp学习第三弹. 明天的计划 协助开发语音存储demo. 还剩下的任务 个人信息数据get. 遇到的困难 困难:整理 ...