The 2021 Sichuan Provincial Collegiate Programming Contest

题目链接:The 2021 Sichuan Provincial Collegiate Programming Contest

A.Chuanpai

题意:定义每一张川牌包含两个数字x, y,并且1 <= x <=  y <= 6,求牌面上数字之和为 n 的牌种类

解题思路:签到,预处理枚举即可

map<int, int> mp;
 
void init(){
	for(int i = 1; i <= 6; i ++){
		for(int j = i; j <= 6; j ++){
			mp[i + j] ++;
		}
	}	
}
void solve(){
	int n;
	cin >> n;
	cout << mp[n] << '\n';
}

 

B. Hotpot

题意:有n名游客,每名游客有一种喜欢的食材,定义操作:

1:当锅内有食材,吃掉全部食材,快乐值+1;

2:当锅内没有食材,向锅内加入食材

一共有m次操作,第n个人操作后由第一个人操作,求最后每个人的快乐值

解题思路:分类讨论即可,如果喜欢某种食材的人数为u

1:当u为偶数:那么只有当游客位于第偶数个喜欢这种食材的位置时才能增加快乐值

2:当u为奇数:

  (1)当游客位于第奇数个喜欢这种食材的位置,他只能增加 lun / 2 的快乐值

  (2)当游客位于第偶数个喜欢这种食材的位置,他可以增加 lun / 2 + (lun & 1)的快乐值

void solve(){
	int n, k, m;
	cin >> n >> k >> m;
	vector<int> a(n + 1), h(n + 1);
	map<int, int> mp, m1;
	for(int i = 1; i <= n; i ++){
		cin >> a[i];
		mp[a[i]] ++;
	}
	for(int i = 1; i <= n; i ++){
		m1[a[i]] ++;
		int lun = m / n + (m % n >= i);
		if(mp[a[i]] & 1){
			if(m1[a[i]] & 1){
				h[i] = lun / 2;
			}
			else{
			    h[i] = lun / 2 + (lun & 1);
			}
		} 
		else{
			if(m1[a[i]] & 1) h[i] = 0;
			else h[i] = lun;
		}
	}
	
	for(int i = 1; i <= n; i ++){
		cout << h[i];
		if(i != n) cout << ' ';
	}
	cout << '\n';
}

 

D. Rock Paper Scissors

题意:a,b玩石头剪刀布,每个人都有一些三种类型的牌,a先手,b可以看见a的牌然后出牌,a希望最小化b的得分,b喜欢最大化得分,求最终答案

(胜利+1, 平局不变, 失败-1)

解题思路:模拟即可,b的出牌策略和a的出牌方式无关,贪心的先求胜利,然后求平局,最后再减去失败的(好像写的很麻烦)

int a[5], b[5];
 
void solve(){
	for(int i = 1; i <= 3; i ++) cin >> a[i];
	for(int i = 1; i <= 3; i ++) cin >> b[i];
	int ans = 0;
	
	if(a[1] <= b[2]){
		b[2] -= a[1];
		ans += a[1];
		a[1] = 0;
	}
	else{
		ans += b[2];
		a[1] -= b[2];
		b[2] = 0;
		if(a[1] <= b[1]){
			b[1] -= a[1];
			a[1] = 0;
		}
		else{
			a[1] -= b[1];
			b[1] = 0;
			ans -= a[1];
			b[3] -= a[1];
			a[1] = 0;
		}
	}
//	cout << ans << '\n';
	if(a[2] <= b[3]){
		ans += a[2];
		b[3] -= a[2];
		a[2] = 0;
	}
	else{
		ans += b[3];
		a[2] -= b[3];
		b[3] = 0;
		if(a[2] <= b[2]){
			b[2] -= a[2];
			a[2] = 0;
		}
		else{
			a[2] -= b[2];
			b[2] = 0;
			ans -= a[2];
			b[1] -= a[2];
			a[2] = 0;
		}
	}
//	cout << ans << '\n';
	if(a[3] > 0){
		ans = ans + b[1] - b[2];
	}
	
	cout << ans << '\n';	
}

 

D. Nihongo wa Muzukashii Desu

题意:对应后缀查找替换

解题思路:模拟即可,注意划横线的特判(读题大挑战)

string check1(string &s){
	if(s.size() >= 5 && s.size() < 7){
		string s1 = s.substr(s.size() - 5, 5);
		if(s1 == "imasu"){
			string s2 = s.substr(0, s.size() - 5);
			return s2 + "tte";
		}
	}
	if(s.size() >= 6){
		string s1 = s.substr(s.size() - 6, 6);
		string s2 = s.substr(0, s.size() - 6);
		if(s1 == "rimasu"){
			return s2 + "tte";
		}
		else if(s1 == "mimasu"){
			return s2 + "nde";
		}
		else if(s1 == "bimasu"){
			return s2 + "nde";
		}
		else if(s1 == "nimasu"){
			return s2 + "nde";
		}
		else if(s1 == "kimasu"){
			return s2 + "ite";
		}
		else if(s1 == "gimasu"){
			return s2 + "ide";
		}
	}
	if(s.size() >= 7){
		string s1 = s.substr(s.size() - 7, 7);
		string s2 = s.substr(0, s.size() - 7);
		if(s1 == "chimasu"){
			return s2 + "tte";
		}	
		else if(s1 == "shimasu"){
			return s2 + "shite";
		}	
	}
}
 
void solve(){
	string s;
	cin >> s;
	if(s == "ikimasu"){
		cout << "itte\n";
		return;
	}
	string ans = check1(s);
	cout << ans << '\n';
}

 

K. K-skip Permutation

题意:构造一个长度为n的排列,要求P+ k = P(i + 1)

解题思路:贪心即可

int a[N], b[N];
 
void solve(){
	int n, k;
	cin >> n >> k;
	int u = 0;
	for(int i = 1; i <= n; i ++){
		if(b[i] == 0){
			for(int j = i; j <= n; j += k){
				a[++ u] = j;
				b[j] = 1;
			}
		}
	}
	
	for(int i = 1; i <= n; i ++) cout << a[i] << ' ';
}

 

L. Spicy Restaurant

题意:每家火锅店的火锅有一个辣度,每位顾客在其中一个火锅店,求到他们能接受的火锅店的最近距离是多少

解题思路:注意到 w 的范围很小,肯定从这里入手,先通过BFS求 dist[i][j],也就是第 i 个火锅店到辣度为 j 的火锅店的最短距离,然后类似于前缀和的方式处理一下 dist[i][j] = min(dist[i][j], dist[i][j - 1]),然后 dist[i][j] 就算第 i 家火锅店到小于等于 j 辣度的火锅店的最短距离

vector<int> edge[N];
int n, m, q, w[N];
int dist[N][110];
bool st[N];
 
void bfs(int u){
	queue<int> q;
	for(int i = 1; i <= n; i ++){
		if(w[i] == u){
			q.push(i);
			dist[i][u] = 0;
		}
	}//所有辣度为u的入队 
	
	while(!q.empty()){
		int x = q.front();
		q.pop();
		for(auto v : edge[x]){
			if(dist[v][u] == INF){
				q.push(v);
			}
			dist[v][u] = min(dist[v][u], dist[x][u] + 1);
		}//更新所有点到辣度为u的最小距离 
	}
}
 
void solve(){
	memset(dist, 0x3f, sizeof dist);
	cin >> n >> m >> q;
	for(int i = 1; i <= n; i ++) cin >> w[i];
	while(m --){
		int u, v;
		cin >> u >> v;
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	for(int i = 1; i <= 100; i ++){
		bfs(i);
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= 100; j ++){
			dist[i][j] = min(dist[i][j], dist[i][j - 1]);
		}
	}//因为是小于等于,求min 
	while(q --){
		int p, a;
		cin >> p >> a;
		if(dist[p][a] == INF) cout << -1 << '\n';
		else cout << dist[p][a] << '\n'; 
	}
}

 

M. True Story

题意:四个变量,n, k, x, p0,分别表示有 n 名乘客,他们距离机场的距离都是 x,飞机的起飞时间是p0,但是飞机会有k次改变起飞时间的通告,并且每次通告都是在 t[i] 发布,并且发布新的起飞时间 p[i],接下来输入 n 个整数 s[i],表示每位乘客的速度,最后分别读入 t[i],p[i]。同时,每位乘客只有在计算得出自己能赶上飞机后才会开始行动,求最终有多少人能赶上飞机

解题思路:先预处理出每位乘客到机场所需要的时间并且排序,然后 k 次更新起飞时间,计算当前距离起飞剩余的时间,然后每次二分来计算能赶上飞机的人数,然后求最大的能赶上飞机的人数

int n, k, x, p0;
int s[N], t[N], p[N], ned[N];
 
void solve(){
	cin >> n >> k >> x >> p0;
	for(int i = 1; i <= n; i ++){
		cin >> s[i];
		ned[i] = x / s[i];
		if(x % s[i] != 0) ned[i] ++;
	}
	for(int i = 1; i <= k; i ++) cin >> t[i];
	for(int i = 1; i <= k; i ++) cin >> p[i];
	sort(ned + 1, ned + n + 1);
	int r = upper_bound(ned + 1, ned + n + 1, p0) - ned - 1;
	for(int i = 1; i <= k; i ++){
		p0 = p[i] - t[i];
		r = max(r, upper_bound(ned + 1, ned + n + 1, p0) - ned - 1);
	}
	cout << r << '\n';
}

 

剩下的题目待补

posted @ 2024-01-18 22:09  Rosmontis_L  阅读(8)  评论(0编辑  收藏  举报