码迷,mamicode.com
首页 > 其他好文 > 详细

CF671C Ultimate Weirdness of an Array 数论、线段树

时间:2019-09-11 00:01:24      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:答案   序列   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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!