2024.11.9 NFLS 学习笔记
2024.11.9 NFLS 学习笔记
空间计算
\(int: 32bits = 4 Bytes\)
\(8bits = 1B\)
\(1KB = 1024B\)
下面代码可大致算出数组 \(A\) 的空间为多少 \(MB\)。
#include <iostream>
using namespace std;
bool st;
int A[1024 * 1024 / 4];
bool ed;
int main()
{
cout << (&st - &ed) / 1024.0 / 1024 << endl;
return 0;
}
输出
1.00003
学习题目
D. 最可能的排名
题目
题目描述
在一场比赛中,我们知道所有对手的得分,我们估计自己的得分在低值和高值之间是等可能的任何整数值,包括这两个值。我们想知道自己的最可能排名。我们将排名定义为 \(1\) 加上超过我们的对手数量,所以如果没有人超过我们(即使有人和我们打平),我们的排名就是 \(1\)。
给定一个整数数组 scores,代表我们对手的得分,以及整数 \(low\) 和 \(high\) ,返回我们最可能的排名。如果有多个最可能的排名,返回-1。
输入格式
scores 数组的长度
整数数组 scores
整数 \(low\)
整数 \(high\)
输出格式
整数
样例
样例1
输入
3
3 12 4
8
8
输出
2
样例2
输入
3
3 4 5
3
7
输出
1
样例3
输入
3
3 4 5
2
5
输出
-1
数据范围
scores将包含 \(1\) 到 \(50\) 个元素,包括两端。scores的每个元素将在 \(0\) 到 \(1,000,000,000\) 之间,包括两端。- \(low\) 将在 \(0\) 到 \(1,000,000,000\) 之间,包括两端。
- \(high\) 将在 \(low\) 和 \(1,000,000,000\) 之间,包括两端。
\(33\%\) 的数据满足,\(high-low\) 不超过 \(2 \times 10^6\)。
解题
思路很简单,直接上代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int NR = 60;
long long a[NR], b[NR];
int rka[NR];
int ans = -1, cnt = 0;
long long mx = 0;
bool flag = false;
bool cmp(long long x, long long y)
{
return x > y;
}
void update(int rk, long long rep)
{
//cout << rk << " " << rep << endl;
if (rep > mx)
{
cnt = 1;
mx = rep;
ans = rk;
}
else if (rep == mx)
{
cnt ++;
}
}
int main()
{
int n;
scanf("%d", &n);
int m = n;
for (int i = 1; i <= n; i ++)
{
scanf("%lld", &a[i]);
b[i] = a[i];
}
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1, cmp);
n = unique(a + 1, a + n + 1) - a - 1;
long long l, r;
scanf("%lld%lld", &l, &r);
sort(a + 1, a + n + 1, cmp);
int it = 0;
for (int i = 1; i <= m; i ++)
{
if (b[i] != b[i - 1])
{
it ++;
rka[it] = i;
}
}
/*for (int i = 1; i <= n; i ++)
{
cout << a[i] << " " << rka[i] << endl;
}*/
rka[n + 1] = m + 1;
a[n + 1] = 0;
if (l >= a[1]) ans = 1;
if (r < a[n]) ans = m + 1;
for (int i = 1; i <= n; i ++)
{
if (i < n && a[i] > r && a[i + 1] <= l)
{
ans = rka[i + 1];
}
if (a[i] > r) continue;
if (a[i] <= l) continue;
if (!flag)
{
int rk = rka[i];
long long rep = r - a[i] + 1;
update(rk, rep);
flag = true;
}
if (a[i + 1] <= l)
{
int rk = rka[i + 1];
long long rep = a[i] - l;
update(rk, rep);
}
else
{
int rk = rka[i + 1];
long long rep = a[i] - a[i + 1];
update(rk, rep);
}
}
//cout << ans << " " << mx << " " << cnt << endl;
if (cnt > 1) puts("-1");
else printf("%d\n", ans);
return 0;
}
\(\Large \textcolor{red}{但值得注意的是,在这里处理边界时要格外关注溢出!}\)
rka[n + 1] = m + 1;
a[n + 1] = 0;
if (l >= a[1]) ans = 1;
if (r < a[n]) ans = m + 1;
F. 限制内存问题
题目
题目描述
你将获得一个包含 \(n\) 个整数的数组 X。然后,你会得到一些查询。
每个查询由一个整数 \(q\) 描述。查询的答案是数组 X 中第 \(q\) 小的元素。这里,\(q\) 是基于 \(0\) 的索引。
也就是说,\(q=0\) 意味着我们想要最小的元素,\(q=1\) 是第二小的,以此类推。
现在这个任务看起来可能太简单了。毕竟,你可以简单地对数组 X 进行排序,然后你就可以在常数时间内回答每个查询。
这是问题的难点:这个问题的内存限制非常小。只有1MB内存。小到你甚至不能将数组 X 存储在内存中。
你会得到整数 \(n\)、\(x_0\)、\(a\) 和 \(b\)。
你还会得到整数数组 query,包含查询。
使用以下伪代码生成数组 X:
X[0] = x0
for i = 1 to n-1:
X[i] = (X[i-1] * a + b) % (1000000007)。
(注意整数溢出。)
返回给定查询的所有答案的总和。
输入格式
整数 \(n\) 整数 \(x_0\) 整数 \(a\) 整数 \(b\)
查询的长度 整数数组 query
输出格式
答案
样例
输入
5
123456789
987654321
1000000006
4
0 1 2 3
输出
733028692
样例解释
X \(= \{123456789, 259106858, 113077375, 244317875, 252176653 \}\)
解题
考虑到不能存储 X 数组,所以可以多次生成。
考虑 值域分块。
最开始先生成一次 X,在各个块上标记出来。
之后对于每次询问,先扫一遍所有块,找到第 \(q\) 大的块的编号 \(p\)。之后再次生成 X 数组,统计第 \(p\) 块中出现的数的位置,最后枚举块 \(p\),找到第 \(q\) 大的位置。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int NR = 1e9 + 10;
const int SR = sqrt(NR) + 10;
const long long mod = 1000000007;
int S = sqrt(1e9 + 7);
int bl[SR], cnt[SR];
int main()
{
int n;
scanf("%d", &n);
int x0, a, b;
scanf("%d%d%d", &x0, &a, &b);
int x = x0;
for (int i = 1; i <= n; i ++)
{
bl[x / S] ++;
x = (1ll * x * a + b) % mod;
}
int m;
scanf("%d", &m);
long long ans = 0;
while (m --)
{
int q;
scanf("%d", &q);
int sum = 0;
int p = -1;
for (int i = 0; i < S; i ++)
{
if (sum <= q && q < sum + bl[i])
{
p = i;
break;
}
sum += bl[i];
}
memset(cnt, 0, sizeof(cnt));
int x = x0;
for (int i = 1; i <= n; i ++)
{
if (1ll * p * S <= x && x < 1ll * (p + 1) * S) cnt[x - 1ll * p * S] ++;
x = (1ll * x * a + b) % mod;
}
long long now = 0;
for (int i = 0; i < S; i ++)
{
if (sum <= q && q < sum + cnt[i])
{
now = 1ll * p * S + i;
break;
}
sum += cnt[i];
}
ans += now;
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号