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 ...
随机推荐
- nat模式下更改网络环境, 虚拟机中Linux无法上网的问题
出现的问题: 1.ifconfig -a 命令下会出现eth0信息中无ip地址等等信息: 2.无法ping通baidu,也就是无法上网: 3.ping 8.8.8.8 提示 connect:netwo ...
- fiddler不同代理模式的区别
Fiddler有不同的代理模式,分为以下两种: 流模式(Streaming)和缓冲模式(Buffering). 流模式可以理解为一种实时通信的模式,有请求就有返回,也就是实时返回. 缓冲模式是等所有请 ...
- 向listview控件中添加数据库数据
//连接字符串 string str = "Data Source=.;Initial Catalog=mu;User ID=sa;Password=111"; //创建数据库连接 ...
- Tuple类型的使用
1.什么是Tuple Tuple类型,可以存放任何类型 2.Tuple有哪些分类 .Net 4.0 定义了8个泛型Tuple类,和一个Tuple静态类 3.Tuple的使用
- Objective-C设计模式——桥接Bridge(接口适配)
桥接模式 桥接模式就是让抽象和实现分离的最好体现,符合面向对象的依赖倒转原则.Abstruct抽象类负责设计客户端接口,Implementor则负责具体的细节逻辑. 在桥接模式中,Abstruct类持 ...
- Android中出现Error:In (declare-styleable) FontFamilyFont, unable to find attribute android:font
Android中出现Error:In (declare-styleable) FontFamilyFont, unable to find attribute android:font 解决办法,今天 ...
- 用antlr4来实现《按编译原理的思路设计的一个计算器》中的计算器
上次在公司内部讲<词法分析——使用正则文法>是一次失败的尝试——上午有十几个人在场,下午就只来了四个听众. 本来我还在构思如何来讲“语法分析”的知识呢,但现在看来已不太可能. 这个课程没有 ...
- Ansible基于playbook批量修改主机名实战
Ansible基于playbook批量修改主机名 安装Ansible,相信这里也不用多说,大家都知道 说一下环境:这里的主机名是修改之后的,我先把其他两台的主机名改为别的 192.168.30.21 ...
- 60s倒计时
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- C++ string使用
在c语言里,我们使用一个字符串时,是通过字符数组或者字符指针的方式来进行使用,在C++里,标准模板库已经给我们提供了string类型(string是以类的方式提供给我们使用). 定义和初始化strin ...