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 ...
随机推荐
- mysql之distinct
记录一下这几天看mysql必知必会的小知识点: 关于mysql查询不同的行 比如记录表中 查询有多少个城市 可能查出很多城市 可以用distinct 来解决这个问题 SELECT DISTINCT c ...
- 【css】回想下经典的布局
看到这张图相信大多数人都很熟悉,这曾经是一种经典的布局方式,一道经典的面试题,一般形如"实现一个布局,左右固定宽度,中间自适应".随着岁月的流转,时光的交替(颇有一种“天下风云出我 ...
- Lightoj 1020 - A Childhood Game (博弈)
题目链接: 1020 - A Childhood Game 题目描述: Alice和Bob在玩弹珠游戏,两人轮流拿走弹珠,每次只能拿走一个或者两个,当Alice作为先手时谁拿走最后一个就是输家,而Bo ...
- 莫队算法 Gym - 100496D Data Mining
题目传送门 /* 题意:从i开始,之前出现过的就是之前的值,否则递增,问第p个数字是多少 莫队算法:先把a[i+p-1]等效到最前方没有它的a[j],问题转变为求[l, r]上不重复数字有几个,裸莫队 ...
- ACM_寒冰王座(完全背包)
寒冰王座 Time Limit: 2000/1000ms (Java/Others) Problem Description: 不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票) ...
- .Net MVC之间的关系以及如何运用
.Net MVC组成部分:视图(views)模型(model)控制器(controller)以及路由(RouteConfig),视图跟模型的数据不进行直接的交互,他们是通过控制器进行视图模型之间的数据 ...
- es6数值扩展
1. 二进制和八进制表示法 从 ES5 开始,在严格模式之中,八进制就不再允许使用前缀0表示,ES6 进一步明确,要使用前缀0o表示. ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0 ...
- git上手简洁手册
下载安装git 创建文件夹:learngit 用Git CMD进入文件夹: cd learngit 用Git CMD初始化git: git init 创建文件:新建一个文件在learngit文件夹下, ...
- SQL 语句在存储过程执行和在SSMS中执行的差异
SQL 语句在存储过程执行和在SSMS中执行的差异 SSMS是SQlSerever management studio.本文所述情形在SQLServer2008中测试. 有时发现同样几条语句,在SSM ...
- interface与抽象类
抽象类: 定义:在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类 抽象类不能被实例化. 抽象类被继承之后,子类必 ...