强智杯--HNCPC2020(A、B、D、G、I)

这次 vp 我队出了 5 题,应当能拿铜,但是还不够,银牌也应当争取。 总之一个原则,保铜争银吧

A - 2020

在这里插入图片描述
在这里插入图片描述
水题不解释。

#include<bits/stdc++.h>

using namespace std;

int main()
{
	int n; string s;
	while(cin >> n)
	{
		cin >> s;
		s = " " + s;
		int cnt = 0;
		for(int i = 1; i <= n - 3; ++i)
		{
			string tmp = s.substr(i, 4);
			if(tmp == "2020"){
				++cnt;
				i = i + 3;
			}
		}
		cout << cnt << '\n';
	}
	
	return 0;
}

B - 2020 vs 2018

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
由于 “2020” 和 “2018” 两者比较显著好判断的区别在于 “2018” 有个 “1”,因此只需判断字符画中是否能找到 “1” 即可。

#include <bits/stdc++.h>

using namespace std;
const int N = 55;
char g[N][N];
int n, m;

void solve()
{
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			cin >> g[i][j];
		}
	}
	
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			if(g[i][j] == 'o')
            {
				if(g[i][j + 1] != 'o' && g[i][j - 1] != 'o')
				{
					if(g[i - 1][j] != 'o')
					{
						puts("2018");
						return ;
					}
				}
			}
		}
	}
	puts("2020");
}

int main()
{
	while(cin >> n >> m)
	{
		solve();
	}
	
	return 0;             
}

D - String Commutativity

在这里插入图片描述
在这里插入图片描述
做法

  • 利用字符串哈希求出每个字符串的最小循环节,并将所有循环节的哈希映射值丢到一个哈希桶中(unordered_map),最后按照 “小朋友握手” 原则统计输出即可求解。

为什么要求循环节?

  • 因为只有当一对字符串 s1、s2 的最小循环节相同时,才会满足 s1 + s2 = s2 + s1。因此我们将所有字符串的循环节放到哈希桶中计数,就能求出所有满足题意的字符串对数。
#include <bits/stdc++.h>

using namespace std;
#define int long long
#define map unordered_map
typedef unsigned long long ull;
const int N = 1e6 + 10, M = N << 1, P = 1331;
int n;
ull h[M], p[M];

ull get(int l, int r)
{
	return h[r] - h[l - 1] * p[r - l + 1];
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);

	while (cin >> n)
	{
		int t = n;
		map<ull, int> hah;
		while (t--)
		{
			string s; cin >> s; s = " " + s + s;

			p[0] = 1;
			for (int i = 1; i <= s.size() - 1; ++i)
			{
				h[i] = h[i - 1] * P + s[i];
				p[i] = p[i - 1] * P;
			}

			int len = (s.size() - 1) / 2;
			for (int i = 2; i <= len + 1; ++i)
			{
				int a = i, b = i + len - 1;
				if (get(1, len) == get(a, b))
				{
					hah[get(1, a - 1)]++;
					break;
				}
			}
		}

		int res = 0;
		for (auto vv : hah)
		{
			res += vv.second * (vv.second - 1) / 2;
		}
		printf("%lld\n", res);
	}

	return 0;
}

G - 奇矩阵

在这里插入图片描述
在这里插入图片描述
根据数据范围,暴力即可。

#include <bits/stdc++.h>

using namespace std;
const int N = 1010, M = 1010;
int n, m;
int a[N][N];

inline void solve()
{
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= m; ++j)
		{
			scanf("%d", &a[i][j]);
		}
	}
	
	for(int i = 1; i <= n - 1; ++i)
	{
		for(int j = i + 1; j <= n; ++j)
		{
			int sum = 0;
			for(int k = 1; k <= m; ++k)
			{
				sum += abs(a[i][k] - a[j][k]);
			}
			if((sum & 1) == 0){
				puts("No");
				return ;
			}
		}
	}
	puts("Yes");
	return ;
}

signed main()
{
	while(~scanf("%d%d", &n, &m))
	{
		solve();
	}
	
	return 0;
}

I - 共线点

在这里插入图片描述
在这里插入图片描述
这是一道计算几何题,首先谈谈一般计算几何有什么坑点

  • 由于这类题目用到的变量一般是 double 型,因此我们要避免对变量进行过多运算,能用一个式子算出答案的就不要用多个式子,这样可以有效避免精度丢失而 wa 的问题。
  • 另外,直线方程的选择也是有讲究的,如果已知两点那就用两点式,这样也可以减少运算避免精度问题。

思路:

将第一根线段左端点和第二根线段右端点联立出第一条直线方程,将第一根线段右端点和第二根线段左端点联立出第二条直线方程。

另第三条线段所在直线与上面求出来的两条直线求交点,两个交点形成的线段与第三根线段如果有交集,则表示有一条直线能够同事穿过三根线段,反之没有。

写代码的时候要尽可能用一个式子算答案,简化代码。

#include <bits/stdc++.h>

using namespace std;
typedef long double db;
db a1, b1, Y1, a2, b2, y2, a3, b3, y3;

bool check(db a, db b, db c, db d)
{
    if (a > c) swap(a, c), swap(b, d);
    return c <= b;
}

inline void solve()
{
	db xx = (y3 - y2) / (Y1 - y2) * (b1 - a2) + a2;
	db yy = (y3 - y2) / (Y1 - y2) * (a1 - b2) + b2;
	if (check(xx, yy, a3, b3)) puts("Yes");
	else puts("No");
}

signed main()
{
	while (cin >> a1 >> b1 >> Y1 >> a2 >> b2 >> y2 >> a3 >> b3 >> y3)
	{
		solve();
	}

	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值