CF671C. Ultimate Weirdness of an Array
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的和。
需要一个线段树。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<math.h>
#include<vector>
//#include<iostream>
using namespace std; int n;
#define maxn 200011
#define LL long long
int a[maxn];
vector<int> s[maxn]; int prime[maxn],lp=,xiao[maxn];bool notprime[maxn];
void pre(int n)
{
for (int i=;i<=n;i++)
{
if (!notprime[i]) prime[++lp]=i,xiao[i]=i;
for (int j=;j<=lp && 1ll*i*prime[j]<=n;j++)
{
xiao[i*prime[j]]=prime[j];
notprime[i*prime[j]]=;
if (!(i%prime[j])) break;
}
}
} int sep[maxn],lsep,numofsep[maxn];
void dfs(int cur,int num,int idx)
{
if (cur>lsep) {s[num].push_back(idx);return;}
dfs(cur+,num,idx);
for (int i=,tmp=sep[cur];i<=numofsep[cur];i++,tmp*=sep[cur]) dfs(cur+,num*tmp,idx);
} struct SMT
{
struct Node
{
int ls,rs;
LL sum,be,Max,Min;
}a[maxn<<];
int size;
SMT() {size=;}
void up(int x)
{
const int &p=a[x].ls,&q=a[x].rs;
a[x].sum=a[p].sum+a[q].sum;
a[x].Max=max(a[p].Max,a[q].Max);
a[x].Min=min(a[p].Min,a[q].Min);
}
void build(int &x,int L,int R)
{
x=++size;
if (L==R) {a[x].ls=a[x].rs=; a[x].sum=a[x].Min=a[x].Max=L; a[x].be=; return;}
const int mid=(L+R)>>;
build(a[x].ls,L,mid); build(a[x].rs,mid+,R); up(x);
}
void build() {int x;build(x,,n);}
int ql,qr; LL v;
void modmaxsingle(int x,int L,int R,LL v)
{
a[x].sum=(R-L+)*v;
a[x].Max=a[x].Min=v;
a[x].be=v;
}
void down(int x,int L,int R)
{
const int &p=a[x].ls,&q=a[x].rs,mid=(L+R)>>;
if (a[x].be) {modmaxsingle(p,L,mid,a[x].be); modmaxsingle(q,mid+,R,a[x].be); a[x].be=;}
}
void Modmax(int x,int L,int R)
{
if (a[x].Min>=v) return;
if (ql<=L && R<=qr && a[x].Max<=v)
{
modmaxsingle(x,L,R,v);
return;
}
down(x,L,R);
const int mid=(L+R)>>;
if (ql<=mid) Modmax(a[x].ls,L,mid);
if (qr> mid) Modmax(a[x].rs,mid+,R);
up(x);
}
void modmax(int L,int R,LL v)
{
ql=L; qr=R; this->v=v;
Modmax(,,n);
}
}t; LL h[maxn];
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%d",&a[i]);
pre();
for (int i=;i<=n;i++)
{
int tmp=a[i];
lsep=;
while (tmp>)
{
if (sep[lsep]!=xiao[tmp]) sep[++lsep]=xiao[tmp],numofsep[lsep]=;
else numofsep[lsep]++;
tmp/=xiao[tmp];
}
dfs(,,i);
}
t.build();
for (int g=;g;g--)
{
int size=s[g].size();
if (size>)
{
t.modmax(s[g][]+,n,n+);
t.modmax(s[g][]+,s[g][],s[g][size-]);
t.modmax(,s[g][],s[g][size-]);
}
h[g]=1ll*n*(n+)-t.a[].sum;
}
LL ans=;
for (int i=;i<=;i++) ans+=i*(h[i+]-h[i]);
printf("%lld\n",ans);
return ;
}
set也能写。不会。
CF671C. Ultimate Weirdness of an Array的更多相关文章
- 【CodeForces】671 C. Ultimate Weirdness of an Array
[题目]C. Ultimate Weirdness of an Array [题意]给定长度为n的正整数序列,定义一个序列的价值为max(gcd(ai,aj)),1<=i<j<=n, ...
- 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 ...
- Ultimate Weirdness of an Array CodeForces - 671C (gcd,线段树)
大意: 定义一个数列的特征值为两个数gcd的最大值, $f(l,r)$表示数列删除区间$[l,r]$的元素后剩余元素的特征值, 求$\sum_{i=1}^n\sum_{j=i}^n{f(i,j)}$ ...
- Codeforces 671C. Ultimate Weirdness of an Array(数论+线段树)
看见$a_i\leq 200000$和gcd,就大概知道是要枚举gcd也就是答案了... 因为答案是max,可以发现我们很容易算出<=i的答案,但是很难求出单个i的答案,所以我们可以运用差分的思 ...
- Codeforces 671C - Ultimate Weirdness of an Array(线段树维护+找性质)
Codeforces 题目传送门 & 洛谷题目传送门 *2800 的 DS,不过还是被我自己想出来了 u1s1 这个 D1C 比某些 D1D 不知道难到什么地方去了 首先碰到这类问题我们肯定考 ...
- Segment Tree Beats 区间最值问题
Segment Tree Beats 区间最值问题 线段树一类特殊技巧! 引出:CF671C Ultimate Weirdness of an Array 其实是考试题,改题的时候并不会区间取最值,区 ...
- CF上的3道小题(1)
CF上的3道小题 终于调完了啊.... T1:CF702E Analysis of Pathes in Functional Graph 题意:你获得了一个n个点有向图,每个点只有一条出边.第i个点的 ...
- Codeforces Round #352 (Div. 2) ABCD
Problems # Name A Summer Camp standard input/output 1 s, 256 MB x3197 B Different is Good ...
随机推荐
- 在sql语句中使用关键字
背景 开发过程中遇到了遇到了一句sql语句一直报错,看了一下字段名和表名都对应上了,但是还是一直报错 sql语句如下: update table set using = ""hh ...
- Akka源码分析-Cluster-Singleton
akka Cluster基本实现原理已经分析过,其实它就是在remote基础上添加了gossip协议,同步各个节点信息,使集群内各节点能够识别.在Cluster中可能会有一个特殊的节点,叫做单例节点. ...
- 【杂文】C++头文件加速
[杂文]C++头文件加速 骚年,冲钱送开挂哦,可以助你超神于OI战场 如果你发现你的暴力超时了的话,可以尝试用一下头文件加速,说不定就过了呢! #pragma once//只编译一次 #pragma ...
- vue开发环境和生产环境里面解决跨域的几种方法
什么是跨域 跨域指浏览器不允许当前页面的所在的源去请求另一个源的数据.源指协议,端口,域名.只要这个3个中有一个不同就是跨域. 这里列举一个经典的列子: #协议跨域 http://a.baidu. ...
- Java多线程(五)停止线程 在沉睡中停止线程
在沉睡中停止线程会抛出异常 public class SleepInterruptDemo extends Thread { public void run() { super.run(); try ...
- 程序 从存储卡 内存卡 迁移到 SD卡
程序 从存储卡 内存卡 迁移到 SD卡 如果你想移动其他软件,在应用市场界面,点击“管理 > 应用搬家”,点击需要转移的应用旁边的“移至SD卡”即可.
- 273 Integer to English Words 整数转换英文表示
将非负整数转换为其对应的英文表示,给定的输入是保证小于 231 - 1 的.示例:123 -> "One Hundred Twenty Three"12345 -> & ...
- [译]Cookies Without Chocolate Chips
Cookies Without Chocolate Chips In the HTTP sense, a cookie is a name with an associated value. A se ...
- [ NOI 2002 ] Robot
\(\\\) Description \(\\\) Solution 垃圾语文题毁我青春 这题其实就是重定义了俩函数.... 首先 \(\varphi(1)=0\) . 然后 \(2\) 在计算 \( ...
- LR接口测试---Java Vuser之增删改查
import lrapi.lr; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Prepared ...