codeforces比赛(1):codeforces 918_div4

发布时间 2023-12-29 12:40:13作者: Tom-catlll

A、Odd One Out

跳转原题点击此:A题地址

1、题目大意

  给你三个数,其中两个是相等的,问你还有一个不相等的数是多少。

2、题目解析

  直接暴力枚举即可,只要找到两个数相等,那么答案就是另一个数。

#include<bits/stdc++.h>

using namespace std;

int T;
int a, b, c;

void solve()
{
	cin >> a >> b >> c;
	if(a == b)
		cout << c << endl;
	else if(a == c)
		cout << b << endl;
	else
		cout << a << endl;
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

 

B、Not Quite Latin Square

跳转原题点击此:B题地址

1、题目大意

  给定一个3X3的矩阵各由3个A、B、C组成,并且每行每列不能相同。这时拿走一个并用\(?\)代替,问你拿走的这个字符是什么。

2、题目解析

  因为每次最多9个字符,所以输入的时候统计下,只要哪个字符不等于3个,那答案就是他

#include<bits/stdc++.h>

using namespace std;

int T;

void solve()
{
	char f[10][10];
	int ff[5] = {0};
	for(int i = 1; i <= 3; i++)
	{
		for(int j = 1; j <= 3;j ++)
		{
			cin >> f[i][j];
			if(f[i][j] != '?')
			{
				char tmp = f[i][j] - 'A' + 1;
				ff[tmp] ++ ;
			}
		}
	}
	for(int i = 1; i <= 3; i++)
	{
		if(ff[i] != 3)
		{
			cout << char('A' + i - 1) << endl;
			return;
		}
	}
	
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}
	return 0;
}

 

C、Can I Square?

跳转原题点击此:C题地址

1、题目大意

  Calin由n个桶,每个桶里面有\(a_i\)\(1 * 1\)积木,问你所有的积木全部用上能否拼成一个正方形

2、题目解析

  只需要判断所有积木加起来能否被完全开方,因为要拼成正方形,所以每个正方形面积就是:1、4、6、...、以此类推。
  要注意两个点:1、sqrt只能用于浮点数开方,并且返回的可能有小数,所以要判断;2、double类型的数据范围是-2^1024 ~ +2^1024,比long long 大,所以放心全部累加吧。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
int T;
int n;
double f[N];

void solve()
{
	cin >> n;
	double tmp = 0;
	for(int i = 1; i <= n; i++)
	{
		cin >>f[i];
		tmp += f[i];
	}
	
	ll x = sqrt(tmp);	// 去除开方后的小数部分(如果有的话)
	if(x * x == tmp)	// 如果等于原数据,说明开方后是没有小数的
		cout << "YES" << endl;
	else
		cout << "NO" << endl;
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

 

D、Unnatural Language Processing

跳转原题点击此:D题地址

1、题目大意

  Lura想创造一种新的语言,该语言包含\(a、e作为v元音\)\(b、c、d作为C辅音\),要求创造的音节只能是 CV 两个字符 或者 CVC 三个字符,当Lura创造好单词后,发现需要用 “.”来将单词分为音节,请你帮他分。

2、题目解析

  因为题目保证是肯定有答案的,所以我们从后往前判断,找到符合条件的就通过数组记录下来。例如我们找到V音节的,就需要找到后面是C字节的;找到C字节的,就需要找到第二个C字节的。最后在输出即可。

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5+10;

int T;
int n;
bool st[N];

void solve()
{
	string s;
	cin >> n >> s;
	memset(st, 0, sizeof st);
	
	int x = 0;
	for(int i = s.size() - 1; i >= 0; i--)
	{
		// 用X记录是找哪种形式,然后找对于音节的头
		if(x == 1)
		{
			if(s[i] == 'b' || s[i] == 'c' || s[i] == 'd')
			{
				st[i] = true;
				x = 0;
				continue;
			}
		}
		
		if(s[i] == 'a' || s[i] == 'e')	// 来寻找CV形式的音节
		{
			x = 1;
			continue;
		}
		else if(s[i] == 'b' || s[i] == 'c' || s[i] == 'd')	// 寻找cvc形式的音节
		{
			x = 1;
			continue;
		}
	}
	for(int i = 0; i < s.size(); i++)
	{
		if(st[i] == 1 && i != 0)	// 注意第一个不输入分隔符
			cout << "." << s[i];
		else
			cout << s[i];
	}
	cout << "\n";
	
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

 

E、Romantic Glasses

跳转原题点击此:E题地址

1、题目大意

  有n杯果汁,其中Iulia只喝奇数杯的,她男朋友只喝偶数杯。Iulia想要选中某个区间的果汁,使得该区间的奇数杯果汁总量之和等于偶数杯果汁之和,问你是否存在该区间。

2、题目解析

  我们只需要通过map存入奇数杯和偶数杯的某个区间差异,只要差异值重复过,说明肯定存在某个区间相等。
  1、那如何更新差异值:即通过sum不断加减奇偶的果汁数;
  2、那如何保证该差异值是某个区间的差异值:注意是通过奇偶的相加相减抵消了这种差异:
  例如:[6,3,1,3,2]:第一次:sum为6,第二次:sum为3,第三次:sum为4,第四次:sum为1,第五次:sum为3。此时sum为3出现过,说明找到了正确区间。这是因为,第二次sum为3时,到最终重复3,这个从l=3到r=5这个区间的奇数杯和偶数杯果子加减为0,所以重复3。

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

int T;
int n;

void solve()
{
	cin >> n;
	vector<ll> a(n + 1);
	for(int i = 1; i <= n; i++)
		cin >> a[i];

	// 即将奇数和偶数杯的果子差异存入mp中
	// 只要出现过这种差异,就赋值为1
	map<ll, ll> mp;
	mp[0] = 1;	// 初始差异为0,存入
	
	// 注意开ll,数据比较大
	ll sum = 0;	// sum是用来表示奇数杯和偶数杯的果子差异
	for(int i = 1; i <= n; i++)
	{
		// 根据奇偶的不同更新差异值
		if(i & 1)
			sum += a[i];
		else
			sum -= a[i];
		// 只要发现出现的差异曾经出现过,说明肯定存在答案
		if(mp[sum] == 1)
		{
			cout << "YES" << endl;
			return;
		}
		mp[sum] = 1;
	}
	cout << "NO" << endl;
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

 

F、题目

跳转原题点击此:F题地址

1、题目大意

  有n个人,这几个人每个人都从各自的起点(\(a_i\))一每次1格的速度到各自的终点(\(b_i\)),并且保证(\(a_i < b_i\) 和 每个人的起点与终点不会有重复)。当两个人相遇时,会打招呼。问你一共打了几次招呼。

2、题目解析

  由于起点和终点不会重复 且 速度都是一样的,所以只有当到达某个人的终点时,双方才会打招呼。并且当自己的路程包含了其他的人时,说明打的招呼人数就是包含里的人总和
  所以我们对起点排序,当起点较小时找到他的终点在原始数组的下标(这代表在原始数组排名第几,比他小的就是大的招呼人数)。
  注意:代码有点极限,不要用longlong开数组,会超时。

#include<bits/stdc++.h>

using namespace std;

#define _1 first
#define _2 second

typedef pair<int, int>pii;

int T;
int n;

void solve()
{
	cin >> n;
	vector<pii> a(n);	// 注意sort是全部,所以不要多开
	vector<int> b(n);
	for(int i = 0; i < n; i++)
	{
		cin >> a[i]._1 >> a[i]._2;
		b[i] = a[i]._2;
	}
	
	sort(a.begin(), a.end());	// 按照起始位置排序
	sort(b.begin(), b.end());	// 按照终点位置排序
	
	long long ans = 0;
	for(int i = 0; i < n; i++)
	{
		int end = a[i]._2;
		// lower_bound 找到第一个大于等于end的地址,减去头地址,返回下标
		// tmp:表示在该人起点较小时,所有比该人终点小的,都会碰见。
		int tmp = lower_bound(b.begin(), b.end(), end) - b.begin();
		// 加上的是下标(代表有几个人前面,因为是从0开始,所以无需减一)
		ans += tmp;
		// 去除该人
		b.erase(b.begin() + tmp, b.begin() + tmp + 1);
	}
	cout << ans << endl;
	
}

int main()
{
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

 

G、Bicycles

跳转原题点击此:G题地址

这是一道Dijkstra的题目,我目前水平无法写出来,我只会套用dijk模板,未来补上。