• 2020 CCPC-Wannafly Winter Camp Day3 ---H. 火山哥的序列


    2020 CCPC-Wannafly Winter Camp Day3 ---H. 火山哥的序列

    题意:

    解法:

    显然是要枚举每个gcd来计算贡献的。我们考虑从大向小枚举gcd,这样可以避免重复计算。我们将gcd设为g。对于每个g,我们可以得到序列中它的倍数a[1],a[2]...,a[k-1],a[k]。
    考虑删除区间,至少留下的情况可能是a[1]和a[2],a[1]和a[k],a[k-1]和a[k]。即对于1~a[1]位置的为左端点,右端点最多可以删到a[k-1]-1,对于a[1]+1-a[2]的数为左端点,最多可以山道a[k]-1,对于a[2]+1-n位置为左端点,可以删到n。这样我们可以维护每个位置最多删到哪,每次更新,多出来的区间就是以g为gcd的贡献。

    #include <bits/stdc++.h>
    #define ll long long
    #define lson rt << 1
    #define rson rt << 1 | 1
    using namespace std;
    const int maxn = 2e5;
    int n,m;
    
    struct node {
    	ll sum;
    	int fm,sm,cnt;
    }tree[4 * maxn + 11];
    
    int pos[maxn + 11];
    
    void push_up(int rt) {
    	tree[rt].sum = tree[lson].sum + tree[rson].sum;
    	if (tree[lson].fm < tree[rson].fm) {
    		tree[rt].fm = tree[lson].fm; tree[rt].cnt = tree[lson].cnt;
    		tree[rt].sm = min(tree[lson].sm , tree[rson].fm);
    	}
    	else if (tree[lson].fm > tree[rson].fm) { 
    		tree[rt].fm = tree[rson].fm; tree[rt].cnt = tree[rson].cnt;
    		tree[rt].sm = min(tree[rson].sm , tree[lson].fm);
    	} 
    	else {
    		tree[rt].fm = tree[rson].fm; tree[rt].cnt = tree[rson].cnt + tree[lson].cnt;
    		tree[rt].sm = min(tree[rson].sm , tree[lson].sm);
    	}
    } 
    
    void upd(int rt,int val) {
    	if (tree[rt].fm >= val) return;
    	tree[rt].sum += 1ll * (val - tree[rt].fm) * tree[rt].cnt;
    	tree[rt].fm = val;
    }
    
    void push_down(int rt) {
    	upd(lson , tree[rt].fm);
    	upd(rson , tree[rt].fm);
    } 
    
    void build(int rt,int l,int r) {
    	if (l == r) {
    		tree[rt].sum = 0;
    		tree[rt].fm = l - 1; tree[rt].sm = n + 1; tree[rt].cnt = 1;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson , l , mid);
    	build(rson , mid + 1 , r);
    	push_up(rt);
    }
    
    void update(int rt,int l,int r,int al,int ar,int val) {
    	if (l > ar || r < al || tree[rt].fm >= val) return;
    	if (l >= al && r <= ar && tree[rt].sm >= val) { upd(rt , val); return; }
    	int mid = (l + r) >> 1;
    	push_down(rt);
    	update(lson , l , mid , al , ar , val);
    	update(rson , mid + 1 , r , al , ar , val);
    	push_up(rt);
    } 
    
    int main(){
    	int t;
    	scanf("%d" , &t);
    	while (t--) {
    		scanf("%d" , &n);
    		m = 0;
    		for (int i = 1; i <= maxn; i++) pos[i] = 0;
    		for (int i = 1; i <= n; i++) {
    			int x;
    			scanf("%d" , &x);
    			pos[x] = i; m = max(m , x);
    		}
    		build(1 , 1, n);
    		ll ans = 0;
    		for (int g = m; g >= 1; g--) {
    			int a = n + 1; int b = n + 1;
    			int c = 0; int d = 0;
    			for (int i = g; i <= m; i += g){
    				if (!pos[i]) continue;
    				if (pos[i] <= a) { b = a; a = pos[i]; }
    				else if (pos[i] < b) b = pos[i];
    				if (pos[i] >= d) { c = d; d = pos[i]; }
    				else if (pos[i] > c) c = pos[i];
    			}
    			if (b == n + 1) continue;
    			ll num = tree[1].sum;
    			if (c == a) {
    				if (a > 1) update(1 , 1 , n , 1 , a - 1 , a - 1);
    				if (a + 1 <= b - 1) update(1 , 1 , n , a + 1 , b - 1 , b - 1);
    				if (b < n) update(1 , 1 , n , b + 1 , n , n);
    			}
    			else if (c == b) {
    				c = d;
    				update(1 , 1 , n , 1 , a , b - 1);
    				if (a + 1 <= b - 1) update(1 , 1 , n , a + 1 , b , c - 1);
    				update(1 , 1 , n , b + 1 , n , n);
    			}
    			else {
    				update(1 , 1 , n , 1 , a , c - 1);
    				update(1 , 1 , n , a + 1 , b , d - 1);
    				update(1 , 1 , n , b + 1 , n , n);
    			} 
    			num = tree[1].sum - num;
    			ans += num * g;
    		} 
    		printf("%lld
    " , ans);
    	} 
    } 
    
  • 相关阅读:
    HTML中为何P标签内不可包含块元素?
    js判断鼠标位置是否在某个div中
    拒绝图片延迟加载,爽爽的看美图
    PHP为什么会被认为是草根语言?
    宜信开源微服务任务调度平台(SIA-TASK)
    JSBridge框架解决通信问题实现移动端跨平台开发
    如何运用多阶构建编写优雅的Dockerfile
    Sharding-JDBC 使用入门和基本配置
    程序员笔记|详解Eureka 缓存机制
    程序员笔记|常见的Spring异常分析及处理
  • 原文地址:https://www.cnblogs.com/Embiid/p/12299926.html
Copyright © 2020-2023  润新知