CSP-J第三次模拟赛补题报告

1.比赛概况

比赛共4题,每题100分,共400分。赛时拿到40分,其中T1得40分。

2.比赛过程

开始把T1到T4用几十分钟看了好几遍,感觉都挺难,没啥思路,硬着头皮去做的T1
T1刚开始没想到思路,想到思路了又发现数组要么越界要么爆掉(按我的思路做的话需要2个大小为十亿的数组,但256M最多只能开60000000),就把数组改小了点,细节上还出了点问题,就过了4个点
T2先暴力打的,之后好几轮优化重做,时间复杂度给降到了O(1),题目给的样例也都过了,交上去的不知道为啥一组没过,而且就是WA,没有MLE和TLE的情况
T3时间不太够,就打了3层暴力,结果刚好爆了
T4相关知识没学过,就打了个骗分的代码,没有得分

3.解题报告

T1.数字对应(digit)

题意

给定正整数n与长度为n的序列A,序列A中的每一个数字都对应序列B中的一个数字,该对应具有唯一性,且序列A和B没有重复的数字,求字典序最小的序列B。

分析

暴力枚举,尽量将前面的数字对应成小的数字。即假设当前数字没有对应的数字,那么就从小到大寻找第一 个未出现过的数字,对应到当前数字上。
标记数字是否被使用,可以使用一个大小为 的 bool 数组来表示每一个数字是否出现过,大于
的数字无需记录,因为不可能成为对应的数字。或者使用 map 进行标记。

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, a[N], last = 1;
map<int, int> mp, t;
int main() {
	//freopen
	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d", &a[i]), mp[a[i]]++;}
	for (int i = 1; i <= n; i++) {
		if (t[a[i]])
			printf("%d ", t[a[i]]);
		else {
			while (mp[last])
				last++;
			t[a[i]] = last;
			mp[last] = true;
			printf("%d ", last);
			}
	}
	//fclose
	return 0;
}

(实际上这段代码在极端情况下是会爆的,但因为测试点的原因可以满分)

T2.技能学习(skill)

题意

有n个人,m份学习资料,每人至少k份资料才能学习,每份学习资料每分钟学习1点,最多学习t分钟,最多学习Q点。给定n,m,k,Q,t,求最多能学习的点数

分析

对于任意的n,m,k,Q,t,尽量平均分总是能得出最优解,且2次平均分后都可以分完(余数轮流分到前几个人)

AC代码

#include <algorithm>
#include <cstdio>
#define ll long long
using namespace std;
ll n, m, k, q, t, f1, n1, f2, n2, ans;
int main() {
	//freopen
	scanf("%lld%lld%lld%lld%lld", &n, &m, &k, &q, &t);
	if (m < k) {
		printf("0");
		return 0;
	}
	if (n * k > m)
		n = m / k; // 如果有不足k的,那就只让满足的进行学习
	m -= n * k; // 减去可以学习的人的消耗
	if (m % n) { // 如果不能平分剩下的
		f2 = k + m / n + 1; // f2分多1个
		n2 = m % n; // 人数
	}
	f1 = k + m / n;
	n1 = n - n2;
	ans += min(f1 * t, q) * n1;
	ans += min(f2 * t, q) * n2;
	printf("%lld", ans);
	//fclose
	return 0;
}

T3.等于(equal)

题意

给定一个长度为n的序列,并且序列中每个元素属于 -2,-1,1,2 中的一个。
请问多少个 子数组 满足最大值的绝对值等于最小值的绝对值。

分析

有2种情况:
1.区间内所有数相等
2.区间内最大值和最小值互为相反数
情况一用for循环向后遍历即可
情况而需要在确定左端点的情况下计算右端点的个数来得到区间个数

AC代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5e5 + 10;
const int inf = 0x3f3f3f3f;
ll n, ans, num[maxn];
int nxt[maxn][5];
int startpos, endpos;
// -2 --> 0 // -1 --> 1
// 1 --> 3 // 2 --> 4
int main() {
	//freopen
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	memset(nxt, 0x3f, sizeof nxt);
	for (int i = 1; i <= n; ++i) {
		cin >> num[i];
	}
	ll ret = 1, lst = num[1];
	for (int i = 2; i <= n; ++i) {
		if (num[i] == lst)
			++ret;
		else {
			ans += ret * (ret + 1) / 2;
			ret = 1;
			lst = num[i];
		}
	}
	ans += ret * (ret + 1) / 2;
	for (int i = n; i >= 1; --i) {
		for (int j = 0; j <= 4; ++j)
			nxt[i][j] = nxt[i + 1][j];
		nxt[i][num[i] + 2] = i;
		int maxpos1 = nxt[i][1 + 2], maxpos2 = nxt[i][2 + 2];
		int minpos1 = nxt[i][-1 + 2], minpos2 = nxt[i][-2 + 2];
		startpos = max(maxpos2, minpos2);
		endpos = n + 1;
		if (startpos != inf && startpos < endpos)
		ans += endpos - startpos;
		startpos = max(maxpos1, minpos1);
		endpos = min(min(maxpos2, minpos2), (int)n + 1);
		if (startpos != inf && startpos < endpos)
		ans += endpos - startpos;
	}
	cout << ans << '\n';
	//fclose
	return 0;
}

T4.最小方差

该题涉及部分数学公式及进阶知识点,下面仅展示AC代码。

#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
const int maxn = 1e5 + 10;
ll sum2[maxn], sum1[maxn], sz[maxn], n, res;
vector<int> G[maxn];
void dfs1(int u, int f) {
	for (int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		if (v == f)
		continue;
		dfs1(v, u);
		sz[u] += sz[v];
		sum1[u] += sum1[v];
		sum2[u] += sum2[v];
	}
	sum2[u] += sz[u] + 2 * sum1[u];
	sum1[u] += sz[u];
	sz[u] += 1;
	return;
}
void dfs2(int u, int f, ll s1, ll s2) {
	res = min(res, n * (s2 + sum2[u]) - (sum1[u] + s1) * (sum1[u] + s1));
	for (int i = 0; i < G[u].size(); i++) {
		int v = G[u][i];
		if (v == f)
			continue;
		ll ret1 = sum1[u] - (sum1[v] + sz[v]) + s1;
		ll ret2 = sum2[u] - (sum2[v] + 2 * sum1[v] + sz[v]) + s2;
		ll szu = n - sz[v];
		dfs2(v, u, ret1 + szu, ret2 + 2 * ret1 + szu);
	}
	return;
}
int main() {
	//freopen
	int t;
	cin >> t;
	while (t--) {
		cin >> n;
		for (int i = 1; i <= n; i++) {
			G[i].clear();
			sum1[i] = sum2[i] = sz[i] = 0;
		}
		for (int i = 1; i <= n - 1; ++i) {
			int u, v;
			cin >> u >> v;
			G[u].push_back(v);
			G[v].push_back(u);
		}
		res = LONG_LONG_MAX;
		dfs1(1, 0);
		dfs2(1, 0, 0, 0);
		cout << res << endl;
	}
	//fclose
	return 0;
}

4.赛后总结

这个分数已经很低了,加上我3.4题基本不能明白,以后得重点抓1.2题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值