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. 最可能的排名

link

题目

题目描述

在一场比赛中,我们知道所有对手的得分,我们估计自己的得分在低值和高值之间是等可能的任何整数值,包括这两个值。我们想知道自己的最可能排名。我们将排名定义为 \(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. 限制内存问题

link

题目

题目描述

你将获得一个包含 \(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;
}
posted @ 2024-11-09 21:50  hsy8116  阅读(10)  评论(0)    收藏  举报