标签:答案 序列 char tor 结构 line const 差分 dig
考虑计算\(\forall p \in [0,200000] , \sum\limits_{l} \sum\limits_{r \geq l} [f_{l,r} \leq p]\),这样我们通过差分可以得到最后的答案。
首先不难发现当固定了某个左端点\(l\)和\(p\)之后,满足条件的\(r\)一定是原序列的一段后缀。设\(r_l\)表示当左端点为\(l\)时最小的右端点,那么\(l\)作为左端点对答案的贡献就是\(N+1-r_l\)。
考虑当\(p\)变为\(p-1\)时\(r_x\)会如何变化。这相当于去掉满足\(f_{l,r} = p\)的区间,而这又等价于不能让当前区间之外的部分出现至少\(2\)个\(p\)的倍数。
把所有\(p\)的倍数拿出来形成一个序列\(x_1,x_2,...,x_k\),如果\(k \leq 1\)显然不会做操作,否则区间\([l,r]\)内至少要包含序列中的至少\(k-1\)个位置。也就是说:
1、当\(l > x_2\)时,\(r_l = N + 1\),这表示已经不存在区间满足条件了;
2、当\(l \in (x_1,x_2]\)时,\(r_l = \max\{r_l , x_m\}\),也就是至少要把\(x_2 \sim x_m\)覆盖;
3、当\(l \in [1,x_1]\)时,\(r_l = \max\{r_l , x_{m-1}\}\),也就是至少要把\(x_1 \sim x_{m-1}\)覆盖。
所以我们需要一个数据结构支持区间\(\max\)和区间和。似乎要写jiry树,但是因为\(r_l\)一定是单调不降的,所以在给定覆盖区间和取\(\max\)的值之后被修改的区间一定是一段前缀,于是这个操作就等价于区间赋值了。这个就可以比较优美地实现。
#include<bits/stdc++.h>
using namespace std;
int read(){
int a = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)){a = a * 10 + c - 48; c = getchar();}
return a;
}
#define int long long
const int _ = 2e5 + 7 , M = 2e5;
namespace segt{
int sum[_ << 2] , mrk[_ << 2] , mx[_ << 2] , mn[_ << 2] , sz[_ << 2];
#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
void mark(int x , int val){mrk[x] = mx[x] = mn[x] = val; sum[x] = sz[x] * val;}
void down(int x){if(mrk[x]){mark(lch , mrk[x]); mark(rch , mrk[x]); mrk[x] = 0;}}
void up(int x){sum[x] = sum[lch] + sum[rch]; mx[x] = mx[rch]; mn[x] = mn[lch];}
void init(int x , int l , int r){
sz[x] = r - l + 1;
if(l == r) sum[x] = mx[x] = mn[x] = l; else{init(lch , l , mid); init(rch , mid + 1 , r); up(x);}
}
void mdy(int x , int l , int r , int L , int R , int val){
if(L > R || mn[x] >= val) return;
if(l >= L && r <= R && mx[x] <= val) return mark(x , val);
down(x);
if(mid >= L) mdy(lch , l , mid , L , R , val);
if(mid < R) mdy(rch , mid + 1 , r , L , R , val);
up(x);
}
}using namespace segt;
int N , arr[_] , ans[_]; vector < int > ys[_] , pos[_];
signed main() {
N = read();
for(int i = 1 ; i <= M ; ++i)
for(int j = 1 ; j * i <= M ; ++j)
ys[i * j].emplace_back(i);
for(int i = 1 ; i <= N ; ++i){int id = read(); for(auto t : ys[id]) pos[t].emplace_back(i);}
init(1 , 1 , N); ans[M] = (N + 1) * N - sum[1];
for(int i = M ; i ; --i){
if(pos[i].size() > 1){
mdy(1 , 1 , N , pos[i][1] + 1 , N , N + 1);
mdy(1 , 1 , N , pos[i][0] + 1 , pos[i][1] , pos[i][pos[i].size() - 1]);
mdy(1 , 1 , N , 1 , pos[i][0] , pos[i][pos[i].size() - 2]);
}
ans[i - 1] = (N + 1) * N - sum[1];
}
int sum = 0; for(int i = 1 ; i <= M ; ++i) sum += (ans[i] - ans[i - 1]) * i;
cout << sum; return 0;
}
CF671C Ultimate Weirdness of an Array 数论、线段树
标签:答案 序列 char tor 结构 line const 差分 dig
原文地址:https://www.cnblogs.com/Itst/p/11503508.html