【21CSPJ普及组】复赛真题

T1 分糖果(candy)

题意:

这里是引用

法1: 暴力枚举 90pt

枚举L ~ R 中每种情况的,找到最优解。

#include<bits/stdc++.h>

using namespace std;

int main(){
	int n, L, R;
	cin >> n >> L >> R;

	int res = 0;
	for(int i = L; i <= R; i++){
		res = max(res, i % n);
	}
	cout << res << endl;
		
	return 0;
}

法2:发现规律 100pt

我们先找到最靠近L的一个n的倍数 x,那么 x - 1 可能是最优解,然后我们去判断 x - 1 的范围,如果在 L ~ R 之间,那么直接输出这个数 % n 也就是 n - 1,如果不在边界内,那我们就判断是要取右边界还是左边界 + n - 1。

#include<bits/stdc++.h>

using namespace std;

int main(){
	int n, L, R;
	cin >> n >> L >> R;

	int res = 0;
	res = (L + n - 1) / n * n;
	res -- ;
	if(res < L){
		if(R - L >= n - 1){
			cout << n - 1 << endl;
		}
		else cout << R % n << endl;
	}
	else {
		if(res <= R)cout << n - 1 << endl;
		else cout << R % n << endl;
	}
		
	return 0;
}

T2 插入排序(sort)

题意:

这里是引用

法1:模拟排序过程 40pt

当是操作1的时候直接修改,因为会保留下来,当是操作2的时候进行一次选择排序,注意提前备份和排序后取消备份,因为他不会保留下来。然后暴力模拟。

#include<bits/stdc++.h>

using namespace std;
const int N = 8e3 + 10;
int a[N], p[N], np[N];
int b[N], bp[N], bnp[N];
int main(){
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		p[i] = np[i] = i;
	}	
	
	while(m --){
		int t;
		cin >> t;
		if(t == 1){
			int c, x;
			cin >> c >>x;
			a[c] = x;	
		}
		else {
			int x;
			cin >> x;
			// 备份 
			memcpy(b, a, sizeof a);
			memcpy(bp, p, sizeof p);
			memcpy(bnp, np, sizeof np);
			// 模拟排序 
			for(int i = 2; i <= n; i ++){
				for(int j = i ; j >= 2; j --){
					if(a[j - 1] > a[j]){
						swap(a[j], a[j - 1]);
						np[p[j]] = j - 1;
						np[p[j - 1]] = j;
						swap(p[j], p[j - 1]);	
					}
				}
			}
			cout << np[x] << endl; 
			memcpy(a, b, sizeof b);
			memcpy(p, bp, sizeof bp);
			memcpy(np, bnp, sizeof bnp);
		}
	}
	
	return 0;
}


法2:排序过程中维护p和np数组 100pt

  1. 当我们修改一个点的时候,需要在这个点的排序后的位置往后往前进行迭代。其中p数组表示,排序后的 i 位置 在原数组的位置p[i]。np数组表示排序后的原数组i的位置在新数组的np[i]。 注意交换顺序。 注意用scanf 用cin会超时。
#include<bits/stdc++.h>

using namespace std;
const int N = 8e3 + 10;
int a[N], p[N], np[N];
int n, m;
// p 排序后 i位置的在原数组的
// np 排序后 原数组的 在新数组
 
void fd(int x){
	for(int i = x; i > 1; i --){
		// 如果 有相等的 按照原数组位置来排序 
		if(a[i - 1] == a[i]  && p[i] > p [i - 1]) continue;
		if(a[i - 1] >= a[i]){
			swap(a[i], a[i - 1]);
			np[p[i]] = i - 1;
			np[p[i - 1]] = i;
			swap(p[i], p[i - 1]);
		}
	}
}
void bk(int x){
	for(int i = x; i < n; i ++){
		// 如果 有相等的 按照原数组位置来排序 
		if(a[i + 1] == a[i]  && p[i + 1] > p [i]) continue;
		if(a[i + 1] <= a[i]){
			swap(a[i], a[i + 1]);
			np[p[i]] = i + 1;
			np[p[i + 1]] = i;
			swap(p[i], p[i + 1]);
		} 
		
	}
}
int main(){

	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		p[i] = np[i] = i;
	}	
	
	//提前进行排序操作。
	for(int i = 2; i <= n; i ++){
		fd(i);
	} 

	while(m --){
		int t;
		scanf("%d", &t);
		if(t == 1){
			int c, x;
			cin >> c >>x;
			c = np[c];
			a[c] = x;
			bk(c);
			fd(c);
		}
		else {
			int x;
			cin >> x;
			cout << np[x] << endl; 
		}
	}
	
	return 0;
}

T3 网络连接(network)

题意:

这里是引用

法1 : 模拟 100pt

我会把我出过错的地方进行标注,注意这些细节!

#include<bits/stdc++.h>
#define int long long // 不开longlong 见祖宗
using namespace std;

map <string, int> mp;

signed main(){
	int n; 
	cin >> n;
	int tt = 1;
	
	for(int i = 1; i <= n; i++){
		map<char, int> cnt;
		string a, b;
		vector<int> v; 
		cin >> a >> b;
		int f = 1;
		string res = "";
		for(int j = 0; j < b.size(); j ++){
			if(b[j] == '.')  res += b[j], cnt['.'] ++;
			else if(b[j] == ':'){
				res += b[j];
				if(cnt['.'] != 3) f = 0;
				// 当出现:时,前面三个.都要出现,也就是。不能出现在:后面
				cnt[':'] ++;
			} 
			else if(b[j] >= '0' && b[j] <= '9'){
				int num = 0;
				int j1 = j;
				string temp = "";
				while(b[j1] <= '9' && b[j1] >= '0' && j1 < b.size()) {
					num = num * 10 ;
					num += b[j1] - '0';
					temp += b[j1];
					j1 ++;
				}
				j = j1 - 1;
				if(temp.size() > 1 && temp[0] == '0')f = 0;//前导0
				res += temp;
				v.push_back(num);
			}
			else f = 0;
		}
		
		for(int i = 0; i < v.size(); i++){
			int num = v[i];
			if(i == v.size() - 1){
				if(num < 0 || num > 65535) f = 0;
			}
			else {
				if(num < 0 || num > 255) f = 0;
			}
		}
		// 。。
		if( f == 0 || v.size() != 5|| cnt['.'] != 3 || cnt[':'] != 1){
			cout << "ERR" << endl;
			continue;
		}
		if(a[0] == 'S'){
			if(mp.find(res) == mp.end()){
				cout << "OK" << endl;
				mp[res] = i;
			}
			else {
				cout << "FAIL" << endl;
			}
		}
		else {
			if(mp.find(res) == mp.end()){
				cout << "FAIL" << endl;
			}
			else {
				
				cout << mp[res] << endl;
			}
		}
	}
	
	return 0;
}

T4 小熊的果篮

题意:

这里是引用

法1: 暴力模拟 70pt

在写这个模拟之前,你要知道规律是 01 交替出现,然后先找到第一个没有拿出的,记录他的种类,然后通过1 - pt 来进行交替互换,然后遍历就行。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 100;
int a[N], vis[N];
int main(){
	int n, sum = 0;
	cin >> n;
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	
	while(sum < n){
		// 先找到第一个没有被拿走的 
		int pt = 0;
		for(int i = 1; i <= n; i++){
			if(!vis[i]) {
			    pt = a[i];
				break;
			}
		}	
		for(int i = 1; i <= n; i++){
			if(!vis[i]) {
				if(pt == a[i]){
					printf("%d ", i);
					sum ++;
					vis[i] = 1;
					pt = 1 - pt;
				}
			}
		}
		cout << endl;		
	}
	
	return 0;
}

法2: SET维护01的位置 100pt

如果0和1都有的话,那么他们肯定是交替出现的,因为如果他们不是交替的话,说明某一种水果已经全部取出。然后使用set中的lowerbound来找到离now最近的一个下标,交替输出同时保证下标递增即可,注意不能用cin cout!

#include<bits/stdc++.h>

using namespace std;
set<int>s[2];

int main(){
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++){
		int x;
		scanf("%d", &x);
		s[x].insert(i);
	}
	
	while(s[0].size() || s[1].size()){
		int pt = 0, now = 0;
		set<int>::iterator s0, s1;
		s0 = s[0].lower_bound(now);
		s1 = s[1].lower_bound(now);
		if(s[0].size() == 0)pt = 1;
		else if(s[1]. size() == 0) pt =0;
		else if(*s0 > *s1) pt = 1;
		else pt = 0;
		while(1){
			auto t2 = s[pt].lower_bound(now);
//			cout << *t2 << endl;
			if(t2 == s[pt].end())break;
			printf("%d ", *t2);
			s[pt].erase(t2);
			now = *t2;
			pt = 1 - pt;
		}
		printf("\n");
	}
	
	return 0;
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值