Codeforces 671C. Ultimate Weirdness of an Array(数论+线段树)
看见$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(数论+线段树)的更多相关文章
- Codeforces 671C - Ultimate Weirdness of an Array(线段树维护+找性质)
Codeforces 题目传送门 & 洛谷题目传送门 *2800 的 DS,不过还是被我自己想出来了 u1s1 这个 D1C 比某些 D1D 不知道难到什么地方去了 首先碰到这类问题我们肯定考 ...
- codeforces 671C Ultimate Weirdness of an Array 线段树+构造
题解上说的很清楚了,我照着写的,表示膜拜题解 然后时间复杂度我觉得应该是O(nlogn),虽然常数略大,预处理和倒着扫,都是O(nlogn) #include <stdio.h> #inc ...
- 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 ...
- CodeForces Round #179 (295A) - Greg and Array 一个线段树做两次用
线段树的区间更新与区间求和...一颗这样的线段树用两次... 先扫描1~k...用线段树统计出每个操作执行的次数... 那么每个操作就变成了 op. l , op.r , op.c= times* ...
- 【CodeForces】671 C. Ultimate Weirdness of an Array
[题目]C. Ultimate Weirdness of an Array [题意]给定长度为n的正整数序列,定义一个序列的价值为max(gcd(ai,aj)),1<=i<j<=n, ...
- [Codeforces 464E] The Classic Problem(可持久化线段树)
[Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...
- CF671C. Ultimate Weirdness of an Array
n<=200000个<=200000的数问所有的f(i,j)的和,表示去掉区间i到j后的剩余的数字中任选两个数的最大gcd. 数论日常不会.. 先试着计算一个数组:Hi表示f(l,r)&l ...
- codeforces 482B. Interesting Array【线段树区间更新】
题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val. 就是区间l---r上的与的值为val,最后问你原来的数 ...
- codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...
随机推荐
- dubbo常见的一些面试题
什么是Dubbo? Duubbo是一个RPC远程调用框架, 分布式服务治理框架 什么是Dubbo服务治理? 服务与服务之间会有很多个Url.依赖关系.负载均衡.容错.自动注册服务. Dubbo有哪些协 ...
- katalon系列十六:代码运行时实时创建元素对象或列表
Katalon的常规方法是先抓取元素并保存到仓库,在脚本中需要用到的时候调取,但假如元素属性和个数是可变的,就不能事先保存到仓库了,需要在脚本运行时实时创建. 代码运行时实时创建一个元素对象的例子im ...
- Scrapy爬豆瓣电影Top250并存入MySQL数据库
d:进入D盘 scrapy startproject douban创建豆瓣项目 cd douban进入项目 scrapy genspider douban_spider movie.douban.co ...
- windows中使用mysql配置my.ini时的坑
windows中安装mysql的一般步骤: mysql版本:5.7.16 1.解压 2.把解压的文件夹bin目录地址添加到环境变量PATH里面 3.在文件加中添加配置文件my.ini——配置内容后面说 ...
- [T-ARA][너 때문에 미쳐][因为你而疯了]
歌词来源:http://music.163.com/#/song?id=5402880 作曲 : 赵英秀/김태현 [作曲 : 赵英秀/k/gim-Tae-hyeon] 作词 : 辉星 [作词 : 辉星 ...
- ES6的新特性(3)——变量的解构赋值
变量的解构赋值 数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). let a = 1; let b = 2; le ...
- 2018-2019-20172329 《Java软件结构与数据结构》第四周学习总结
2018-2019-20172329 <Java软件结构与数据结构>第四周学习总结 经过这样一个国庆节的假期,心中只有一个想法,这个国庆假期放的,不如不放呢!! 教材学习内容总结 < ...
- AJAX请求.net controller数据交互过程
AJAX发出请求 $.ajax({ url: "/Common/CancelTaskDeal", //CommonController下的CancelTaskDeal方法 type ...
- winform界面之固定大小随dpi
场景: 已经更改成大小可随dpi改变,可是在用applyresoures()之后(添加更改语言功能),发现控件大小失真. 分析:applyresoures()是把该控件的属性改为程序设计的固定大小,不 ...
- 半期考html5小游戏制作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...