zoukankan      html  css  js  c++  java
  • 计蒜客 微软大楼设计方案(RMQ)

    题目链接 微软大楼设计方案

    中文题就不说题意了~

    首先是简单版本

    满足$1 <= n, m <= 50$

    那么设$c[i][j]$为从第$i$幢楼到第$j$幢楼的最低的那幢楼的高度

    计算两个点之间的距离的时候,若两个点分别在第$i$列,第$j$列,那么要根据$c[i][j]$来计算。

    暴力即可

    #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)
    
    int n, k;
    int a[10010];
    int c[201][201];
    int x[201], y[201];
    int m;
    int ans = 0;
    
    int main(){
    
    	scanf("%d%d", &n, &k);
    	rep(i, 1, n) scanf("%d", a + i);
    	rep(i, 1, n){
    		c[i][i] = a[i];
    		rep(j, i + 1, n) c[i][j] = min(c[i][j - 1], a[j]), c[j][i] = c[i][j];
    	}
    
    	rep(i, 1, n) rep(j, 1, n) if (c[i][j] == 0) c[i][j] = c[j][i];
    
    	scanf("%d", &m);
    
    	rep(i, 1, m) scanf("%d%d", x + i, y + i);
    
    	rep(i, 1, m - 1){
    		rep(j, i + 1, m){
    			int cnt;
    			if (y[i] > c[x[i]][x[j]] && y[j] > c[x[i]][x[j]])
    				cnt = y[i] - c[x[i]][x[j]] + y[j] - c[x[i]][x[j]] + abs(x[i] - x[j]);
    			else cnt = abs(x[i] - x[j]) + abs(y[i] - y[j]);
    			if (cnt <= k) ++ans;
    		}
    	}
    
    	printf("%d
    ", ans);
    	return 0;
    
    
    
    }
    

    再是中等版本

    满足$1 <= n <= 200000, 1 <= m <= 2000$

    $m$的范围让我们还是可以在1秒钟之内两两枚举点对并完成统计

    就是$c[i][j]$不能按照刚刚那个方法求了。

    我们构建一张ST表,令$f[i][j]$为从$i$开始连续$2^{j}$个数的最小值

    于是在$O(1)$内我们可以得到第$i$幢楼到第$j$幢楼的最低的那幢楼的高度

    中等版本也解决了

    #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)
    
    int a[200030];
    int f[200030][22];
    int n, m, k;
    int ans = 0;
    
    
    struct node{
    	int x, y;
    	void scan(){ scanf("%d%d", &x, &y);}
    	friend bool operator < (const node &a, const node &b){
    		return a.x == b.x ? a.y < b.y : a.x < b.x;
    	}
    } p[3010];
    
    
    inline int solve(int l, int r){
    	int k = (int)log2((double)(r - l + 1));
    	return min(f[l][k], f[r - (1 << k) + 1][k]);
    }
    
    void work(){
    	rep(i, 1, n) f[i][0] = a[i];
    	rep(j, 1, 20) rep(i, 1, n)
    		if ((i + (1 << j) - 1) <= n) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
    
    int main(){
    
    	scanf("%d%d", &n, &k);
    	rep(i, 1, n) scanf("%d", a + i);
    
    	work();
    
    	scanf("%d", &m);
    	rep(i, 1, m) p[i].scan();
    	sort(p + 1, p + m + 1);
    
    	rep(i, 1, m - 1){
    		rep(j, i + 1, m){
    			int cnt;
    			int now = solve(p[i].x, p[j].x);
    			if (p[i].y > now && p[j].y > now)
    				cnt = p[i].y - now + p[j].y - now + abs(p[i].x - p[j].x);
    			else cnt = abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y);
    			if (cnt <= k) ++ans;
    		}
    	}
    
    	printf("%d
    ", ans);
    	return 0;
    
    }
    

    最后是困难版本

    满足$1 <= n <= 200000, 1 <= m <= 200000$

    这个时候不能两两枚举点对来统计了

    注意到$h[i] <= 20$,这是一个很重要的条件

    对于当前在第$i$列的某个点,我们发现在他之后的$max(0, k - 40)$列中的所有点

    这些点不用考虑,一定符合条件

    因位距离最大值为$ k - 40 + max(h[i]) + max(h[j]) <= k$,所以一定符合条件

    同理我们也发现,第$i + k$之后的点肯定不符合条件

    那么我们只要枚举$i + max(0, k - 40) + 1$ 到 $i + k$ 这些列中的所有点就可以了

    做的时候维护一个前缀和即可。

    时间复杂度$O(mlogm + mh^{2})$

    #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)
    
    const int N = 200100;
    
    int a[N];
    int f[N][22];
    int n, m, k;
    long long ans = 0;
    long long c[N];
    int g[N][22];
    
    vector <int> v[N];
    
    struct node{
    	int x, y;
    	void scan(){ scanf("%d%d", &x, &y);}
    	friend bool operator < (const node &a, const node &b){
    		return a.x == b.x ? a.y < b.y : a.x < b.x;
    	}
    } p[N];
    
    inline int solve(int l, int r){
    	int k = (int)log2((double)(r - l + 1));
    	return min(f[l][k], f[r - (1 << k) + 1][k]);
    }
    
    void work(){
    	rep(i, 1, n) f[i][0] = a[i];
    	rep(j, 1, 20) rep(i, 1, n)
    		if ((i + (1 << j) - 1) <= n) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
    
    int main(){
    
    	scanf("%d%d", &n, &k);
    
    	rep(i, 1, n) scanf("%d", a + i);
    
    	work();
    
    	scanf("%d", &m);
    	rep(i, 1, m) p[i].scan();
    	sort(p + 1, p + m + 1);
    	memset(g, 0, sizeof g);
    
    	rep(i, 1, m) ++c[p[i].x];
    	rep(i, 1, n) c[i] += c[i - 1];
    	rep(i, 1, m){
    		v[p[i].x].push_back(i);
    		g[p[i].x][p[i].y] = 1;
    	}
    
    	rep(i, 1, m){
    		rep(j, p[i].y + 1, a[p[i].x]) if (abs(j - p[i].y) <= k && g[p[i].x][j]) ++ans;
    		int cnt = p[i].x + k - 40;
    		if (cnt > n) cnt = n;
    
    		if (cnt > p[i].x){
    			long long xx = c[cnt], yy = c[p[i].x];
    			ans += xx - yy;
    		}
    
    		int now = p[i].x + k;
    		if (now > n) now = n;
    
    
    		rep(j, max(cnt + 1, p[i].x + 1), now){
    
    			for (auto u : v[j]){
    				int cnt;
    				int now = solve(p[i].x, p[u].x);
    				if (p[i].y > now && p[u].y > now)
    					cnt = p[i].y - now + p[u].y - now + abs(p[i].x - p[u].x);
    				else cnt = abs(p[i].x - p[u].x) + abs(p[i].y - p[u].y);
    
    				if (cnt <= k) ++ans;
    
    			}
    
    
    		}
    
    	}
    
    	printf("%lld
    ", ans);
    	return 0;
    
    }
    
  • 相关阅读:
    【转载】[SMS]SMS内容的7bit和UCS2编码方式简介
    【转载】两篇关于字符编码的博文
    【IRA/GSM/UCS2】the difference of IRA/GSM/UCS2 character set
    【LTE】LTE中SINR的理解
    【LTE】为什么使用SNR来表征信道质量,而并不用RSRQ?这两者的区别是什么?
    【C++】C++为什么要引入引用这个复合类型?
    【HTML55】HTML5与CSS3基础教程
    python 三种单例模式
    python3.10 新增的 match case 语句
    Python pyqt5简单的图片过滤工具
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7126673.html
Copyright © 2011-2022 走看看