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其实都是我。
还需要努力呀!