• 倍增专题


    本蒟蒻只会个倍增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;
    }
    

      

  • 相关阅读:
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    第5次作业
    4
    第三次
    2
    11
    第五次作业
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7261682.html
Copyright © 2020-2023  润新知