1024考试总结

1024考试总结

T1

​ 题目大意:

​ 理想的光滑平面上有\(n\)个加速阶段,每个加速阶段的加速度和持续时间分别是\(a[i], t[i]\),现在让你求一种\(n\)个阶段的排列顺序,使得新的顺序的位移比输入的顺序的位移相差最大,输出最大差值.\(n <= 1e5\).

​ 贪心,按\(a[i]\)从大到小排序会得到最优顺序.

​ 证明用临项交换:假设我们要让先\(i\)\(j\)比先\(j\)\(i\)更优,那么:

\(vt_i + \frac{1}{2}a_it_i^2 + (v + a_it_i)t_j + \frac{1}{2} a_jt_j^2 > vt_j + \frac{1}{2}a_jt_j^2 + (v + a_jt_j)t_i + \frac{1}{2} a_it_i^2\)

​ 化简一下就可得到:\(a_i > a_j\).

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 1e5 + 5;
int n;
struct node { int a, t; } x[N], y[N]; 

int cmp(node x, node y) { return x.a > y.a; }

long double calc() {
	long long vx = 0, vy = 0; long double res = 0;
	for(int i = 1;i <= n; i++) {
		res += (1ll * vy * y[i].t + 1ll * y[i].a * y[i].t * y[i].t / 2) - (1ll * vx * x[i].t + 1ll * x[i].a * x[i].t * x[i].t / 2);
		vx += 1ll * x[i].a * x[i].t; vy += 1ll * y[i].a * y[i].t;
	}
	return res;
}

int main() {
	
	n = read();
	for(int i = 1;i <= n; i++) y[i].a = x[i].a = read(), y[i].t = x[i].t = read();
	sort(y + 1, y + n + 1, cmp);
	printf("%.1Lf", calc());
	
	return 0;
}

T2

​ 题目大意:

​ 一个人买咖啡,他需要每个小时都喝一杯热咖啡,共有\(n\)小时,现在每个小时的咖啡价格不同,一杯咖啡可以持续热\(h\)个小时,可以同一个小时买多杯咖啡留给后面喝(只要没有凉就行),问怎么买咖啡可以使总钱数最小,输出从\(b\)\(e\)小时内每个小时买了几杯咖啡.\(n <= 1e5\)

​ 假设我们现在在\(i\)小时,这个小时喝的咖啡肯定是在这个时间段买的:\([i - h + 1, i]\).所以我们要找到这个时间段的最小值的位置,在这个位置给\(i\)位置买一杯咖啡.这样可以花钱最少.所以维护一个单调队列就好了.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 1e5 + 5;
int n, h, b, e;
int a[N], q[N], ans[N];

int main() {
	
	while(cin >> n >> h >> b >> e) {
		for(int i = 1;i <= n; i++) a[i] = read(), ans[i] = 0;
		int l = 1, r = 0;
		for(int i = 1;i <= n; i++) {
			while(l <= r && q[l] <= i - h) l ++;
			while(l <= r && a[q[r]] >= a[i]) r --;
			q[++ r] = i;
			ans[q[l]] ++;
		}
		for(int i = b;i <= e; i++) printf("%d ", ans[i]);
		printf("\n");
	}
	
	return 0;
}

T3

题目链接

​ 题目大意:给你一维,二维,三维空间,再给\(n\)个点,让你求有多少个点对曼哈顿距离不超过\(d\).

​ 一维:直接双指针乱搞一下.

​ 二维:曼哈度距离转切比雪夫距离,\((x, y) -> (x + y, x - y)\),新坐标系里的切比雪夫距离就是原坐标系里的曼哈顿距离.首先按\(x\)从小到大排序,然后暴力枚举\(x\).\(y\)用数据结构维护一下.

​ 三维:还是曼哈顿距离转切比雪夫距离.新增了一维,但是每个点的坐标范围变成了\(1 <= x,y,z <= 75\).我们可以将z看做层数,计算每一层和层与层之间的答案.这样只用把\(x,y\)转化成切比雪夫距离就好了.然后我们每层搞一个二维前缀和.查询的时候可以\(O(1)\)查询.这里不同层的答案和相同层的答案分开处理比较好,因为相同层的答案会算重复.

#include <bits/stdc++.h>

#define ls(o) (o << 1)
#define rs(o) (o << 1 | 1)
#define mid ((l + r) >> 1)

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 1e5 + 5;
int B, n, d, m;
int sum[80][150][150];
long long ans, ans1;
struct node { int x, y, z; } a[N];
struct tree { int sum; } t[N << 4];

int cmp(node a, node b) { return a.x < b.x; }

int dis(int i, int j) {
	if(B == 2) return abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y);
	if(B == 3) return abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y) + abs(a[i].z - a[j].z);
}

void work_B_1() {
	sort(a + 1, a + n + 1, cmp);
	int last = 1, tmp;
	for(int i = 1;i <= n; i++) {
		int j;
		for(j = last;j <= n; j++) 
			if(a[j].x - a[i].x > d) { last = j - 1; break; } 
		ans += j - i - 1;
	}
	printf("%lld", ans);	
}

void up(int o) {
	t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
}

void insert(int o, int l, int r, int x, int f) {
	if(l == r) { t[o].sum += f; return ; } 
	if(x <= mid) insert(ls(o), l, mid, x, f);
	if(x > mid) insert(rs(o), mid + 1, r, x, f);
	up(o);
}

int query(int o, int l, int r, int x, int y) {
	if(x <= l && y >= r) { return t[o].sum; }
	int res = 0;
	if(x <= mid) res += query(ls(o), l, mid, x, y);
	if(y > mid) res += query(rs(o), mid + 1, r, x, y);
	return res;
}

void work_B_2() { 
	for(int i = 1;i <= n; i++) {
		int x = a[i].x, y = a[i].y;
		a[i].x = x + y; a[i].y = x - y;
	}
	sort(a + 1, a + n + 1, cmp);
	int last = 1; insert(1, -m, m, a[1].y, 1);
	for(int i = 2;i <= n; i++) {
		while(last < i && a[i].x - a[last].x > d) 
			insert(1, -m, m, a[last].y, -1), last ++;
		ans += query(1, -m, m, a[i].y - d, a[i].y + d);
		insert(1, -m, m, a[i].y, 1);
	}
	printf("%lld", ans);
}

void work_B_3() { 
	for(int i = 1;i <= n; i++) {
		int x = a[i].x, y = a[i].y;
		a[i].x = x + y; a[i].y = x - y + m; 
		sum[a[i].z][a[i].x][a[i].y] ++;
	}
	for(int i = 1;i <= m; i++)
		for(int j = 1;j <= 2 * m; j++)
			for(int k = 1;k <= 2 * m; k++) sum[i][j][k] += sum[i][j - 1][k] + sum[i][j][k - 1] - sum[i][j - 1][k - 1];
	for(int i = 1;i <= n; i++) {
		for(int j = max(1, a[i].z - d);j < a[i].z; j++) {
			int D = d - (a[i].z - j);
			int x1 = max(1, a[i].x - D), x2 = min(2 * m, a[i].x + D);
			int y1 = max(1, a[i].y - D), y2 = min(2 * m, a[i].y + D);
			ans += sum[j][x2][y2] - sum[j][x1 - 1][y2] - sum[j][x2][y1 - 1] + sum[j][x1 - 1][y1 - 1];
		}
		int D = d;
		int x1 = max(1, a[i].x - D), x2 = min(2 * m, a[i].x + D);
		int y1 = max(1, a[i].y - D), y2 = min(2 * m, a[i].y + D);
		ans1 += sum[a[i].z][x2][y2] - sum[a[i].z][x1 - 1][y2] - sum[a[i].z][x2][y1 - 1] + sum[a[i].z][x1 - 1][y1 - 1];
	}
	printf("%lld", ans + (ans1 - n) / 2);
}

int main() {
	
	B = read(); n = read(); d = read(); m = read();
	if(B == 1) for(int i = 1;i <= n; i++) a[i].x = read();
	if(B == 2) for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read();
	if(B == 3) for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read(), a[i].z = read();
	if(B == 1) { work_B_1(); }
	if(B == 2) { work_B_2(); }
	if(B == 3) { work_B_3(); }
	
	return 0;
}
posted @ 2020-10-25 07:26  C锥  阅读(83)  评论(0编辑  收藏  举报