• ECNU 3480 没用的函数 (ST表预处理 + GCD性质)


    题目链接  ECNU 2018 JAN Problem E

    这题卡了双$log$的做法

    令$gcd(a_{i}, a_{i+1}, a_{i+2}, ..., a_{j}) = calc(i, j)$

    根据最大公约数的性质我们知道一个数和另一个数求$gcd$之后如果变小了,那么结果小于等于之前那个数的$1/2$

    所以在考虑$a_{i}$的时候,

    $calc(1, i), calc(2, i), calc(3, i), ..., calc(i, i)$这些数去重之后最多只有$logC$个不同的数

    在考虑$a_{i}$之前把整个数列看成$logC$段,每一段先与$a_{i}$合并,然后再对每段分别求前缀和的最小值

    (求出来的最小值是要被减去的)

    分别更新答案即可。

    注意特判$0$的情况,为了方便索性我把数列中的$0$都去掉了,出现$0$的话就把初始$ans$设成$0$

    时间复杂度$O(nlogC), C = max(a_{i})$   (这里我忽略了$STL$自带的复杂度)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    typedef long long LL;
    typedef pair <LL, LL> PII;
    
    const int N = 1e6 + 10;
    const int A = 21;
    
    LL a[N], s[N], f[N][A];
    LL ans;
    vector <PII> v1, v2;
    map <LL, LL> mp;
    int n, m, flag;
    int lg[N];
    
    LL gcd(LL a, LL b){
    	return b == 0 ? a : gcd(b, a % b);
    }
    
    void init(){
    	rep(i, 1, n + 1) f[i][0] = s[i - 1];
    	rep(j, 1, 20) rep(i, 1, n + 1)
    		if ((i + (1 << j) - 1) <= n + 1) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
    
    inline LL calc(int l, int r){
    	if (l > r) return 0;
    	int k = lg[r - l + 1];
    	return min(f[l][k], f[r - (1 << k) + 1][k]);
    }
    
    inline void solve(int x, int y){
    	if (!mp.count(x)) mp[x] = y;
    	else mp[x] = min(mp[x], (LL)y);
    }
    
    int main(){
    
    	lg[1] = 0; rep(i, 2, 1e6 + 1) lg[i] = lg[i >> 1] + 1;
    
    	scanf("%d", &n);
    	m = 0;
    	flag = 1;
    	rep(i, 1, n){
    		LL x;
    		scanf("%lld", &x);
    		if (x) a[++m] = x;
    		else flag = 0;
    	}
    	n = m;
    
    	ans = 1ll * flag * (-9e18);
    	rep(i, 1, n) s[i] = s[i - 1] + a[i];
    	init();
    
    	rep(i, 1, n){
    		LL cnt = abs(a[i]);
    		mp.clear();
    		for (auto u : v1) solve(gcd(u.fi, cnt), u.se);
    		solve(cnt, i);
    		v1.clear();
    		for (auto u : mp) v1.push_back(MP(u.fi, u.se));
    		int sz = v1.size();
    
    		for (int j = 0; j < sz; ++j){
    			PII u = v1[j];
    			int r;
    			if (j == sz - 1) r = i; else r = v1[j + 1].se - 1;
    			ans = max(ans, (s[i] - calc(u.se, r)) * u.fi);
    		}
    
    	}
    
    	printf("%lld
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    HDU 5059 Help him
    HDU 5058 So easy
    HDU 5056 Boring count
    HDU 5055 Bob and math problem
    HDU 5054 Alice and Bob
    HDU 5019 Revenge of GCD
    HDU 5018 Revenge of Fibonacci
    HDU 1556 Color the ball
    CodeForces 702D Road to Post Office
    CodeForces 702C Cellular Network
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8424892.html
Copyright © 2020-2023  润新知