UESTC - ACM趣味赛热身赛(二)题解

题解

另附:另一位同学写的题解,其中B题证明更简单


第一题

因为每次只拿两个,所以不改变原来序列的奇偶性。
所以直接判断奇偶性即可。

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int N; scanf("%d", &N);
	if(N % 2 == 0) puts("Yitong_Qin");
	else puts("Xiaoyu_Chen");
	return 0;
}

第二题

我们可以将字符串 S N S N − 1 . . . S 0 S_NS_{N-1}...S_0 SNSN1...S0视为由 S N − 1 . . . S 0 S_{N-1}...S_0 SN1...S0在前方补 S N S_N SN得到的。
也就是说,可以先得到 S N − 1 . . . S 0 S_{N-1}...S_0 SN1...S0的消去情况,再在前面补充一个字符考虑能否消去。

由题意:只要不同的字符相邻且不同,必然可以完成一次消去。从而尽可能完成消去操作后,最后剩余的字符串必然是由一串相同的字符构成

我们假设 S N − 1 . . . S 0 S_{N-1}...S_0 SN1...S0消去后得到的字符串由若干个相同的字符 S S S 构成。假设我们在前方增加了一个字符 S N S_N SN,只有两种可能:

  1. S N S_N SN S S S 相同时,不能执行消去操作,字符串长度加一
  2. S N S_N SN S S S 不同时,由于 S N S_N SN在前,消去后仍然是 S N S_N SN,而后面的字符 S S S个数将减少1。重复这一步骤,会使得字符串变成一个单独的 S N S_N SN.此时字符串长度为1。

从而我们可以倒着从后往前找一遍。如果两个相邻的字符相同word[i] == word [i + 1],那么字符串长度就应该加一,也就是ans[i] = ans[i + 1] + 1,如果不同,则字符串将消为当前位置的字符,消去后字符串长度为1,也就是ans[i] = 1

最后我们输出消至首位的ans[0]即为解。

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 200000 + 10;
char word[MAXN];
int ans[MAXN];

int main()
{
	scanf("%s", word);
	int len = strlen(word);
	ans[len - 1] = 1;
	for(int i = len - 2;i >= 0; --i)
	{
		if(word[i] == word [i + 1])
			ans[i] = ans[i + 1] + 1;
		else
			ans[i] = 1;
	}
	printf("%d\n", ans[0]);
	return 0;
}

第三题

首先,如果 X X X 7 7 7 可以凑24点,则 ( X + 2 ∗ K ) (X + 2 * K) (X+2K) 7 7 7 也可以,只需要在原来的式子后面乘上 ( 7 / 7 ) (7 / 7) (7/7) 就可以了(因为 24 ∗ 1 = 24 24 * 1 = 24 241=24

然后最小成立的奇数个数是7个7,方案是:
7 + 7 + 7 + ( 7 + 7 + 7 ) / 7 = 21 + 3 = 24 7 + 7 + 7 + (7 + 7 + 7) / 7 = 21 + 3 = 24 7+7+7+(7+7+7)/7=21+3=24
最小成立的偶数个数是6个7。
( 7 ∗ 7 ∗ 7 − 7 ) / ( 7 + 7 ) = ( 7 ∗ 48 ) / ( 7 ∗ 2 ) = 24 (7 * 7 * 7 - 7) / (7 + 7) = (7 * 48) / (7 * 2) = 24 (7777)/(7+7)=(748)/(72)=24

所以大于等于6时必然有解。

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int N; cin >> N;
	if(N >= 6) puts("YES");
	else puts("NO");
	return 0;
}

第四题

序列要么是 101010…这样的,要么是 010101…这样的。

我们先讨论一下如何把原序列变成 101010… 这样的序列。

  • 首先,分析我们可以进行两种操作,要么把两个人交换位置,要么把一个人改变属性。考虑到对具体某个人来说,他只存在两种情况,要么站对了位置要么站错了,站对位置的人我们没必要动他,所以我们只需要讨论那些站错了位置的,也就是这个位置应该站0却站了个1这样子。

  • 然后我们发现,对一对站错位置的1和0来说,我们交换他们只需要1次,但分别改变他们却需要2次。也就是说,我们应该尽可能地交换他们。但是站错位置的1和0数量不一定一样,我们尽可能交换完之后,可能还会剩下一些站错位置的人,他们没有可以交换的人了。这时我们只能手动改变他们。

  • 记站错位置的 1 1 1 A A A 个, 0 0 0 B B B 个,不妨设 A &gt; B A&gt;B A>B, 则需要交换 B B B次,此时还有 A − B A - B AB 1 1 1没被处理,因此还需要手动改变 A − B A - B AB次,也就是总共需要 B + ( A − B ) = A B + (A - B) = A B+(AB)=A次。当 B &gt; A B&gt;A B>A时类似,可知需要 B B B次。综上,需要次数为 m a x ( A , B ) max(A, B) max(A,B)次。

  • 010101…的处理方法类似。

我们记改变为101010…的次数为M次,改变成010101…的次数为N次,
那么肯定哪个小选哪个,于是需要次数为 m i n ( M , N ) min(M, N) min(M,N)次。

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 100000 + 10;
int N; char Drivers[MAXN];
int place_1010[2], place_0101[2];
int ans;

void pre()
{
	cin >> N;
	scanf("%s", Drivers);
	for(int i = 0;i < N; ++i)
	{
		if(i % 2 == 0)
		{
			if(Drivers[i] == '1') ++place_1010[1];
			else ++place_0101[0];	
		}
		else
		{
			if(Drivers[i] == '1') ++place_0101[1];
			else ++place_1010[0];
		}
	}
}

int main()
{
	pre();
	ans = min( max(place_1010[0], place_1010[1]), max(place_0101[0], place_0101[1]));
	cout << ans << endl;
	return 0;
} 

第五题

考虑三种情况。

  • 自己只有一张牌

    • 必然胜利,出完就没了。
  • 自己有两张牌。

    • 考虑到对方如果小于等于2张,必须先压制对方的最大牌
      • 此时出完最大牌之后不能被对方压制,一旦对方比自己最大牌大就输了
    • 对方牌比2张多,此时考虑到不论自己出小的还是大的对方都要压制己方最大牌
      • 于是只需要自己小牌比对方第二小的牌大即可
#include<bits/stdc++.h>
using namespace std;

const char poker[20] = { '3', '4', '5', '6', '7', '8',
			'9', 'T', 'J', 'Q', 'K', 'A', '2'};

int find(char ch)
{
	for(int i = 0;i < 13; ++i)
		if(ch == poker[i]) return i + 1;
}

const int MAXN = 20;
char ss1[MAXN], ss2[MAXN];
int pk1[MAXN], pk2[MAXN];
int len1, len2;

void pre()
{
	scanf("%s", ss1);scanf("%s", ss2);
	len1 = strlen(ss1); len2 = strlen(ss2);
	for(int i = 0;i < len1; ++i) pk1[i] = find(ss1[i]);
	for(int i = 0;i < len2; ++i) pk2[i] = find(ss2[i]);
	return;
}

bool ok()
{
	if(len1 == 1) return true;
	if(len2 <= 2)
	{
		if(pk1[1] >= pk2[len2 - 1]) return true;
		else return false;
	}
	if(pk2[1] < pk1[1]) return true;
	return false;
}

int main()
{
	pre();
	if(ok()) cout << "zhong_wang" << endl;
	else cout << "cfeitong" << endl;
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值