zoukankan      html  css  js  c++  java
  • 倍增专题

    本蒟蒻只会个倍增lca,实在太菜了。

    稍微灵活一下的倍增就不会了,所以开一个倍增专题,先把倍增练熟

    1.跑路

    由每次走 2米很容易想到倍增。

    map[k][i][j]表示从i走2k米能否走到 j

    如果 map[k-1][i][l]==1 && map[k-1][l][j] == 1,那么map[k][i][j] == 1

    如果 map[k][i][j]==1 那么就可以一次走过去,dis[i][j]=1

    然后floyd求最短路(其他方法也行,数据小,且floyd好写)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define N 101
    #define min(x, y) ((x) < (y) ? (x) : (y))
    
    int n, m;
    int map[N][N][N], dis[N][N];
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    int main()
    {
    	int i, j, k, l;
    	n = read();
    	m = read();
    	memset(dis, 127 / 3, sizeof(dis));
    	for(i = 1; i <= m; i++) map[0][read()][read()] = 1;
    	for(l = 1; l <= 64; l++)
    		for(k = 1; k <= n; k++)
    			for(i = 1; i <= n; i++)
    				for(j = 1; j <= n; j++)
    					if(map[l - 1][i][k] && map[l - 1][k][j])
    						map[l][i][j] = 1;
    	for(k = 0; k <= 64; k++)
    		for(i = 1; i <= n; i++)
    			for(j = 1; j <= n; j++)
    				if(map[k][i][j])
    					dis[i][j] = 1;
    	for(k = 1; k <= n; k++)
    		for(i = 1; i <= n; i++)
    			for(j = 1; j <= n; j++)
    				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    	printf("%d
    ", dis[1][n]);
    	return 0;
    }
    

    2.[POI2010]ZAB-Frog

    可以用一个队列来求出每个点第k远的点(神奇)

    然后倍增搞,但是MLE,需要滚动数组。

    #include <cstdio>
    #include <iostream>
    #define N 1000001
    #define LL long long
    
    int n, k;
    LL m, a[N];
    int f[2][N], ans[N];
    
    int main()
    {
    	int i, j, l, r;
    	scanf("%d %d %lld", &n, &k, &m);
    	for(i = 1; i <= n; i++) scanf("%lld", &a[i]);
    	f[0][1] = k + 1;
    	l = 1, r = k + 1;
    	for(i = 2; i <= n; i++)
    	{
    		while(r < n && a[i] - a[l] > a[r + 1] - a[i]) l++, r++;
    		f[0][i] = a[i] - a[l] >= a[r] - a[i] ? l : r;
    	}
    	for(i = 1; i <= n; i++) ans[i] = i;
    	for(i = 1; m; i++, m >>= 1)
    		for(j = 1; j <= n; j++)
    		{
    			if(m & 1) ans[j] = f[(i & 1) ^ 1][ans[j]];
    			f[i & 1][j] = f[(i & 1) ^ 1][f[(i & 1) ^ 1][j]];
    		}
    	for(i = 1; i <= n; i++) printf("%d ", ans[i]);
    	return 0;
    }
    

      

    3.开车旅行

    noip超恶心倍增题。

    预处理出来小A和小B在每个位置所到的点,这个可以从后往前扫,将每一个扫到的数放到一个集合里面,因为集合可以自动排好序。

    然后对于i,小A和小B能到的点只有可能是排好序后的i-1,i-2,i+1,i+2。

    开一些倍增数组,因为小A和小B轮流开车,如果开两个倍增数组,一个表示小A,一个表示小B,那么倍增的时候要考虑奇偶性,非常麻烦,所以精妙的地方就来了。

    把A走一次和B走一次合起来,算作一步,开个倍增数组f[N][21],另开两个倍增数组disA[N][21],disB[N][21]表示A和B走2k步的距离。

    对于每一个询问倍增求解即可。

    #include <set>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define N 100001
    #define abs(x) ((x) < 0 ? -(x) : (x))
    
    using namespace std;
    
    double val = ~(1 << 31), A, B;
    int n, m, tmp, cnt, ans = 1, X, S;
    int f[N][21], disA[N][21], disB[N][21], a[N], b[N];
    
    struct node
    {
    	int height, id;
    	bool operator < (const node &a) const
    	{
    		return height < a.height;
    	}
    }h[N + 4];
    
    set <node> s;
    set <node> :: iterator it;
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline bool cmp(node x, node y)
    {
    	return abs(x.height - tmp) < abs(y.height - tmp) || (abs(x.height - tmp) == abs(y.height - tmp) && x.height < y.height);
    }
    
    inline double ask(int x)
    {
    	int i, y = X;
    	A = 0, B = 0;
    	for(i = 20; i >= 0; i--)
    		if(disA[x][i] + disB[x][i] <= y && f[x][i])
    			y -= disA[x][i] + disB[x][i], A += disA[x][i], B += disB[x][i], x = f[x][i];
    	if(disA[x][0] <= y) A += disA[x][0];
    	if(B == 0) return ~(1 << 31);
    	return A / B;
    }
    
    int main()
    {
    	int i, j;
    	double x;
    	n = read();
    	for(i = 1; i <= n; i++)
    	{
    		h[i].id = i;
    		h[i].height = read();
    	}
    	for(i = n; i >= 1; i--)
    	{
    		s.insert(h[i]);
    		it = s.find(h[i]);
    		cnt = 1;
    		tmp = (*it).height;
    		if(it != s.begin())
    		{
    			it--;
    			h[n + cnt++] = *it;
    			if(it != s.begin())
    			{
    				it--;
    				h[n + cnt++] = *it;
    				it++;
    			}
    			it++;
    		}
    		if(++it != s.end())
    		{
    			h[n + cnt++] = *it;
    			if(++it != s.end())
    				h[n + cnt++] = *it;
    		}
    		std::sort(h + n + 1, h + n + cnt, cmp);
    		if(cnt > 1) b[i] = h[n + 1].id;
    		if(cnt > 2) a[i] = h[n + 2].id;
    	}
    	for(i = 1; i <= n; i++)
    		if(a[i])
    		{
    			disA[i][0] = abs(h[i].height - h[a[i]].height);
    			if(b[a[i]])
    				f[i][0] = b[a[i]], disB[i][0] = abs(h[a[i]].height - h[b[a[i]]].height);
    		}
    	for(j = 1; j <= 20; j++)
    		for(i = 1; i <= n; i++)
    			f[i][j] = f[f[i][j - 1]][j - 1],
    			disA[i][j] = disA[i][j - 1] + disA[f[i][j - 1]][j - 1],
    			disB[i][j] = disB[i][j - 1] + disB[f[i][j - 1]][j - 1];
    	X = read();
    	for(i = 1; i <= n; i++)
    	{
    		x = ask(i);
    		if(x < val || (val == x && h[ans].height < h[i].height)) ans = i, val = x;
    	}
    	printf("%d
    ", ans);
    	m = read();
    	for(i = 1; i <= m; i++)
    	{
    		S = read();
    		X = read();
    		ask(S);
    		printf("%d %d
    ", int(A), int(B));
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Atitit attilax要工作研究的要素 纪要 方案 趋势 方向 概念 理论
    Atitit 常见每日流程日程日常工作.docx v7 r8f
    Atitit it 互联网 软件牛人的博客列表
    Atitit 信息链(Information Chain)的概念理解 attilax总结
    Atitit 知识点的体系化 框架与方法 如何了解 看待xxx
    Atitit 聚合搜索多个微博 attilax总结
    Atitit 企业知识管理PKM与PIM
    Atitit 项目沟通管理 Atitit 沟通之道 attilax著.docx
    Atitit 项目管理软件 在线服务 attilax总结 1. 项目管理协作的历史 1 1.1. Worktile 406k 1 1.2. Teambition  584k in baidu
    Atitit.每周末总结 于每周一计划日程表 流程表 v8 import 上周遗漏日志补充 检查话费 检查流量情况 Crm问候 Crm表total and 问候
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7261682.html
Copyright © 2011-2022 走看看