看见$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. Zigbee系列(end device)

    End device设备分为睡眠和非睡眠两种(RxOnWhenIdle标记不同). 入网时的association请求,会使用这个标记. 共同特性 子节点多次发送数据失败(无回应),发送孤点扫描(re ...

  2. 学习HTML 第一节.小试牛刀

    此贴并非教学,主要是自学笔记,所述内容只是些许个人学习心得的记录和备查积累,难以保证观点正确,也不一定能坚持完成. 如不幸到访,可能耽误您的时间,也难及时回复,贴主先此致歉.如偶有所得,相逢有缘,幸甚 ...

  3. 爬虫2.3-scrapy框架-post、shell、验证码

    目录 scrapy框架-post请求和shell 1. post请求 2. scrapy shell 3. 验证码识别 scrapy框架-post请求和shell 1. post请求 scrapy框架 ...

  4. vim神器(学习笔记)

    #本文并非原创,属于本人学习中的记录笔记或是转存笔记,如果涉及到哪位高人的创作权益,敬请海涵! Vim 是一个上古神器,本篇文章主要持续总结使用 Vim 的过程中不得不了解的一些指令和注意事项,以及持 ...

  5. 基于C#的机器学习--模糊逻辑-穿越障碍

    模糊逻辑-穿越障碍 模糊逻辑.另一个我们经常听到的术语.但它的真正含义是什么?它是否意味着不止一件事?我们马上就会知道答案. 我们将使用模糊逻辑来帮助引导一辆自动驾驶汽车绕过障碍,如果我们做得正确,我 ...

  6. 如何报FOB价格

    FOB价格是当货物越过船舷,卖方即完成交货.FOB价格术语仅适用于海运或内河运输.在国际贸易中,FOB价格是比较常用的一种,FOB价格作为众多贸易中的一种需要外贸人员熟悉掌握. FOB价格是当货物越过 ...

  7. 一个网页从输入URL到页面加载完的过程

    过程概述 1.浏览器查找域名对应的IP地址 2.浏览器根据IP地址与服务器建立socket连接 3.浏览器与服务器通信:浏览器请求,服务器处理请求和响应 4.浏览器与服务器断开连接 具体过程 1.搜索 ...

  8. LeetCode 888. Fair Candy Swap(C++)

    题目: Alice and Bob have candy bars of different sizes: A[i] is the size of the i-th bar of candy that ...

  9. "Hello World"团队召开的第三周第七次会议

    今天是我们团队“Hello World!”团队召开的第三周的第七次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.Todo List 六.会议照片 七.燃尽图 一.会议时 ...

  10. Java 将数字转为16进制,然后转为字符串类型 将空格去掉。终结版

    //十进制转为十六进制 public class ArrayTest7 { public static void main(String[] args){ System.out.println(toH ...