zoukankan      html  css  js  c++  java
  • 倍增算法总结 ( 含RMQ模板)

    部分题目来自《算法竞赛设计进阶》

    问题

          给定一个长度为n的数列A,有m个询问,每次给定一个整数T,求出最大的k,满足a[1],a[2]……a[k]的和小于等于T(不会打sigma)

           第一反应是二分,这个时候的复杂度是logn

           还有第二种解法,用倍增的思想,复杂度为logk(所求答案)。显然倍增要好很多。我讲讲倍增。

           如果是暴力的话显然是从前往后一个一个枚举来计算。这里每次只往后移了一格,我们能不能一下子移很多格呢?

           当然可以,我们可以用倍增的思想,第一次移1格,第二次移2格……如果再移就超过答案,就把移的格数除以2。如果最后移的格数是0,那么这一格就是答案

    #include<cstdio>
    #include<cctype>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 100 + 10;
    int a[MAXN], s[MAXN], n, m, sum;
    
    void read(int& x)
    {
        int f = 1; x = 0; char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); } 
        while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); } 
        x *= f;
    }
    
    int main()
    {
        read(n); read(m);
        _for(i, 1, n) read(a[i]), s[i] = s[i-1] + a[i];
        while(m--)
        {
            int T; read(T);
            int k = 0, p = 1, sum = 0; //k为当前在哪一格,p为下一步要移多少格,sum为已经走了的格的总和 
            while(p)
            {
                if(k + p <= n && sum + s[k + p] - s[k] <= T) 
                {
                    sum += s[k + p] - s[k];
                    k += p;
                    p <<= 1;
                }
                else p >>= 1;
            }
            printf("%d
    ", k);
        }
        return 0;
    }

    hihocoder#1384

    发现倍增的套路和二分有点像。出题就出来判断区间是否合法上

    这里值得一提的是可以把新加进入的数组sort一遍,然后和之前已经

    有序的数组做一次归并,而不用从头再来sort

    //这个程序WA,目前还不知道为什么
    #include<cstdio>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
     
    typedef long long ll;
    const int MAXN = 5e5 + 10;
    int n, m, a[MAXN];
    int b[MAXN], t[MAXN];
    ll T;
    
    inline void read(int& x) 
    {
    	int f = 1; x = 0; char ch = getchar();
    	while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
    	while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
    	x *= f;
    }
    
    inline void readll(ll& x) 
    {
    	ll f = 1; x = 0; char ch = getchar();
    	while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
    	while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
    	x *= f;
    }
    
    void merge_sort(int L, int R, int p)
    {
    	_for(i, R + 1, R + p) b[i] = a[i];
    	sort(b + R + 1, b + R + p + 1);
    	
    	int i = L, pos = L, j = R + 1;
    	while(i <= R || j <= R + p)
    	{
    		if(j > R + p || i <= R && a[i] < b[j]) t[pos++] = a[i++];
    		else t[pos++] = b[j++];
    	}
    	_for(i, L, R + p) a[i] = t[i];
    }
    
    bool check(int L, int R, int p)
    {
    	merge_sort(L, R, p);
    	ll res = 0;
    	int l = L, r = R + p, tmp = m;
    	while(tmp--)
    	{
    		if(l >= r) break;
    		res += (a[r] - a[l]) * (a[r] - a[l]);
    		if(res > T) return false;
    		r--; l++;
    	}
    	return true;
    }
     
    int main()
    {
    	int t; read(t);
    	while(t--)
    	{
    		read(n); read(m); readll(T);
    		_for(i, 1, n) read(a[i]);
    	
    		int L = 1, R, ans = 0, p;
    		while(L <= n)
    		{
    			R = L; p = 1;
    			ans++;
    	   		while(p)
    	   		{
    	   	   		if(R + p <= n && check(L, R, p)) //
    	   	   		{
    	   	   	   		R += p;
    			   		p <<= 1;
    		   		}
    		   		else p >>= 1;
    	   		} 
    	   		L = R + 1;
    		}
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    }

    RMQ算法模板 poj 3264(快速求区间最值,不支持修改)

    #include<cstdio>
    #include<algorithm>
    #define REP(i, a, b) for(int i = (a); i < (b); i++)
    #define _for(i, a, b) for(int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 8e4;
    const int MAXM = 30;
    int dmin[MAXN][MAXM], dmax[MAXN][MAXM], a[MAXN], n, q;
    
    void RMQ_init()
    {
    	_for(i, 1, n) dmin[i][0] = dmax[i][0] = a[i];
    	for(int j = 1; (1 << j) <= n; j++)
    		for(int i = 1; i + (1 << j) - 1 <= n; i++)
    		{
    			dmax[i][j] = max(dmax[i][j-1], dmax[i + (1 << (j-1))][j-1]);
    			dmin[i][j] = min(dmin[i][j-1], dmin[i + (1 << (j-1))][j-1]);
    		}
    }
    
    int RMQ_ans(int l, int r)
    {
    	int k = 0;
    	while((1 << (k + 1)) <= r - l + 1) k++;
    	return max(dmax[l][k], dmax[r - (1 << k) + 1][k]) - min(dmin[l][k], dmin[r - (1 << k) + 1][k]);
    }
    
    int main()
    {
    	scanf("%d%d", &n, &q);
    	_for(i, 1, n) scanf("%d", &a[i]);
    	RMQ_init();
    	while(q--)
    	{
    		int l, r;
    		scanf("%d%d", &l, &r);
    		printf("%d
    ", RMQ_ans(l, r));
    	}
    	return 0;
    }
  • 相关阅读:
    Atitit.播放系统规划新版本 v4 q18 and 最近版本回顾
    Atitit.播放系统规划新版本 v4 q18 and 最近版本回顾
    atitit.极光消息推送服务器端开发实现推送  jpush v3. 总结o7p
    atitit.极光消息推送服务器端开发实现推送  jpush v3. 总结o7p
    Atitit.文件搜索工具 attilax 总结
    Atitit.文件搜索工具 attilax 总结
    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package
    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package
    Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结
    Atitit..状态机与词法分析  通用分词器 分词引擎的设计与实现 attilax总结
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819319.html
Copyright © 2011-2022 走看看