zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    基于Lucene/XML的站内全文检索解决方案
    内容管理系统(CMS)的设计和选型
    Lucene入门与使用[转]
    为自己的系统搞个全文搜索 参考值:2 (转)
    C# 时间函数
    Lucene倒排索引原理(转)
    什么是内容管理系统CMS?
    网络测试常用命令
    C#与C的区别
    人生致命的八个经典问题
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8424892.html
Copyright © 2011-2022 走看看