test20220416考试总结

T1.数列求和

题面

我们定义一个数列的价值为:数列里中最大的一个数减去最小的一个数。

数列\((3,1,7,2)\) 价值为 \(6\) ;数列\((42,42)\)价值为 \(0\)

现在给你一个数列,要你求出所有连续子数列的价值总和。

对于 \(100\%\)的数据,\(2≤n≤300 000\)

思路

我用的是朴素的单调栈的思路。

开2个单调栈,计算贡献左右端点。然后再乘法原理算总贡献。

时间复杂度是 \(O(n)\),与标程一样。(由于他用了4个单调栈,所以常数mine更优秀)

代码

// O(n)
#include <bits/stdc++.h>
#define int long long
using namespace std;

int a[300005];
int l[300005], r[300005];
int ll[300005], rr[300005];
int n;
int top, top2;
int st[300005];
int st2[300005];
long long ans;
//int ans1,ans2;
signed main() {
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		r[i] = n + 1;
		rr[i] = n + 1;
	}
	for (int i = 1; i <= n; ++i) {
		while (top && a[st[top]] > a[i]) {
			r[st[top--]] = i;
		}
		l[i] = st[top];
		st[++top] = i;
	}
	for (int i = 1; i <= n; ++i) {
		while (top2 && a[st2[top2]] < a[i]) {
			rr[st2[top2--]] = i;
		}
		ll[i] = st2[top2];
		st2[++top2] = i;
	}
	for (int i = 1; i <= n; i++) {
		ans -= (r[i] - i) * (i - l[i]) * a[i];
		ans += (rr[i] - i) * (i - ll[i]) * a[i];
	}
	cout << ans << '\n';
	return 0;
}

T2.家庭作业

本题博客

题面

轩轩有太多的作业要做啊!!!!!!!!为了能高效完成作业,规定每项
作业花一个单位时间。

他的学习日从 \(0\) 时刻开始,有 \(100000\) 个单位时间(!)。在任一时刻,他
都可以选择编号 \(1 \sim N\)\(N\) 项作业中的任意一项作业来完成。

因为他在每个单位时间里只能做一个作业,而每项作业又有一个截止日期,
所以他很难有时间完成所有 \(N\) 个作业,虽然还是有可能。
对于第 \(i\) 个作业,有一个截止时间 \(D_i\),如果他可以完成这个作业,那么他
可以获得分数 \(P_i\).

在给定的作业分数和截止时间下,FJ 能够获得的分数最大为多少呢?答案
可能会超过 \(32\) 位整型。

对于 \(100\%\) 的数据,\(1 \le N \le 100000\)
$1 \le D_i \le 100000,1 \le P_i \le 1000000000 $

思路

我用的是朴素的贪心。可是贪心没有最优解(证明:@exited)所以只有20分。

代码

// O(nlogn)
#include <bits/stdc++.h>
using namespace std;

int n;
struct node {
	long long d, p;
	bool operator<(const node ano) const {
		if (d == ano.d) {
			return p > ano.p;
		} else {
			return d < ano.d;
		}
	}
} a[100005];
long long ans = 0, ntime = 0;

int main() {
	freopen("homework.in", "r", stdin);
	freopen("homework.out", "w", stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].d >> a[i].p;
	}
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i++) {
		if (ntime >= a[i].d) {
			continue;
		}
		ans += a[i].p;
		ntime++;
	}
	cout << ans << '\n';
	return 0;
}

T3.排序

题面

给出一个长度为 \(n\) 的数组 \(A\),然后给这个数组排序,排序的过程是每次加入
一个数,然后把当前位置的数向左移动,直到他移动到正确的排好序的位置。

下面是操作的过程:

void insertsort(vector<int>& A) {
	for (int i = 0 ; i < A.size() ; ++i) { //向 A 中插入 A[i]。
		int j = i;
		While (j > 0 && A [j - 1] > A[j]) {
			Swap(A[j - 1], A[ j ]);
			--j;
		}
	}
}

求需要移动的次数。

对于 \(100\%\) 的数据:\(n≤100000,a[i]≤10^9\)

思路

逆序对模板题。用树状数组可过(全机房,除了我过了的人,写的都是归并排序)

代码

// O(nlogn)
#include <bits/stdc++.h>
using namespace std;
long long t[100005], n, rk[100005], ans;

struct node {
	int v, id;
	bool operator<(const node ano) const {
		if (ano.v == v)return id < ano.id;
		else return v < ano.v;
	}
} a[100005];

inline int lowbit(int x) {
	return (x & (-x));
}
int query(int p) {
	int ans = 0;
	while (p) {
		ans += t[p];
		p -= lowbit(p);
	}
	return ans;
}
void update(int p, int v) {
	while (p <= n) {
		t[p] += v;
		p += lowbit(p);
	}
}

int main() {
	freopen("sort.in", "r", stdin);
	freopen("sort.out", "w", stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].v;
		a[i].id = i;
	}
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; i++) {
		rk[a[i].id] = i;
	}
	for (int i = 1; i <= n; i++) {
		update(rk[i], 1);
		ans += (i - query(rk[i]));
	}
	cout << ans << '\n';
	return 0;
}

T4.送分题

题面

你有一个可以调节明暗度的灯泡。这个灯泡有 \(m\) 个明暗度,分别为
\(1,2,3...m\)。灯泡有一个遥控器。你每按一次遥控器,假设灯泡当前亮度为 \(x\)
按一次以后就变成了 \(x+1\),如果 \(x\)\(m\),则按一次以后变成 \(1\)。每个灯泡在设计
时都有一个按钮,且有一个舒适值 \(k\),你可以按一次按钮,无论你现在的亮度是
多少,你的亮度都会变成 \(k\)。按一次按钮或按一次遥控器都算是操作一次,现在
给你一个序列 \(a_1 \sim a_n\),一开始你的亮度是 \(a_1\),然后你要将亮度调到 \(a_2\),再到$ a_3$,
再到 \(a_4\),再到 \(a_5\)...最后到 \(a_n\),完成这个亮度变化的过程会得到一个最小的操
作次数 \(T\),现在问你如何指定舒适值(舒适值指定之后不能改变),使得 \(T\) 最小。

\(T\) 的最小值。

对于 \(60\%\) 的数据: \(n,m≤3000\)

对于 \(100\%\) 的数据: \(2 ≤n,m≤1000000, 1≤a_i≤m, a_i≠a_i+1\)

题面

准备打60分的暴力,结果写挂。一分没捞着。

代码

// O(nm)
#include <bits/stdc++.h>
using namespace std;

long long n, m, ans = LLONG_MAX, nans, a[1000005];

int main() {
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= m; i++) {
		nans = 0;
		for (int j = 1; j <= n; j++) {
			long long uxi = 1, nuxi = 0;
			if (i > a[j]) {
				uxi += m - i + a[j] - 1;
			} else {
				uxi += a[j] - i;
			}
			if (a[j - 1] > a[j]) {
				nuxi  = (m - a[j - 1]) + a[j] - 1;
			} else {
				nuxi = a[j] - a[j - 1];
			}
			nans += min(uxi, nuxi);
		}
		ans = min(ans, nans);
	}
	cout << ans << '\n';
	return 0;
}

总结

这次考试总分400分,拿了220分。

没想到是全班rk1。

rk1、rk2、rk11其实都是我。

还需要努力呀!

posted @ 2022-04-16 15:44  蒟蒻xiezheyuan  阅读(76)  评论(0编辑  收藏  举报