优快云英雄会(平安科技在线编程大赛)部分题目的解析

本文解析了优快云英雄会2014年在线编程大赛的部分题目,包括火车调度、另类编辑距离等,提供了详细的算法思路及C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前些年优快云上有英雄会编程比赛,其中2014年平安科技在线编程大赛,部分题目如下。附上本人的分析和答案。

1. 火车调度

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=584&&ExamID=579

问题分析:

这道题目,官方给出了4星(较难)的难度等级,过分了……

对输入的时刻建立4个链表,分别是:A站出发时刻表、A站到达时刻表、B站出发时刻表、B站到达时刻表。AB站的最小车库存量初始设为AB站各自出发的车列数(即各自站点的出发时刻表的size)。遍历出发列表,对比到达列表,出发前有前序到达,且满足检修时间的,则初始库存数减一。如此,问题得解。

解答:

#include <iostream>
#include <list>

using namespace std;

void fun(unsigned int t, list <unsigned int> a_leave, list <unsigned int> b_arrive,
	list <unsigned int> b_leave, list <unsigned int> a_arrive,
	unsigned int &an, unsigned int &bn)
{
	an = a_leave.size();
	bn = b_leave.size();
	a_leave.sort();
	b_arrive.sort();
	b_leave.sort();
	a_arrive.sort();

	list <unsigned int>::iterator it1 = a_leave.begin();
	list <unsigned int>::iterator it2 = a_arrive.begin();
	while (it1 != a_leave.end())
	{
		if (it2 == a_arrive.end())
			break;
		if (*it1 >= *it2 + t)
		{
			--an;
			++it1;
			++it2;
		}
		else
		{
			++it1;
		}
	}
	it1 = b_leave.begin();
	it2 = b_arrive.begin();
	while (it1 != b_leave.end())
	{
		if (it2 == b_arrive.end())
			break;
		if (*it1 >= *it2 + t)
		{
			--bn;
			++it1;
			++it2;
		}
		else
		{
			++it1;
		}
	}
}

int main()
{
	unsigned int t, na, nb;
	unsigned int hour1, min1, hour2, min2;
	unsigned int an, bn;
	char c;
	list <unsigned int> a_leave, b_arrive, a_arrive, b_leave;

	while (cin >> t)
	{
		if (cin >> na >> nb)
		{
			for (unsigned int i = 0; i < na; i++)
			{
				scanf_s("%2d:%2d %2d:%2d", &hour1, &min1, &hour2, &min2);
				a_leave.push_back(hour1 * 60 + min1);
				b_arrive.push_back(hour2 * 60 + min2);
			}
			for (unsigned int i = 0; i < nb; i++)
			{
				scanf_s("%2d:%2d %2d:%2d", &hour1, &min1, &hour2, &min2);
				b_leave.push_back(hour1 * 60 + min1);
				a_arrive.push_back(hour2 * 60 + min2);
			}
			fun(t, a_leave, b_arrive, b_leave, a_arrive, an, bn);
			cout << an << " " << bn << endl;
			a_leave.clear();
			b_arrive.clear();
			b_leave.clear();
			a_arrive.clear();
		}
	}
	return 0;
}

2. 另类编辑距离

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=580&&ExamID=575

问题分析:

显然,这是一道求最大公共子序列的题目。将两个字符串与公共子串的差相加,即为结果。

解答:

#include <iostream>
#include <string>
using namespace std;

int fun(string str1, string str2)
{
	int row = str1.length()+1;
	int column = str2.length()+1;
	int value;
	int ** martix = new int * [row];
	for (int i = 0; i < row; i++)
	{
		martix[i] = new int [column];
	}


	for (int i = 0; i < row; i++)
	{
		martix[i][0] = 0;
	}
	for (int j = 0; j < column; j++)
	{
		martix[0][j] = 0;
	}


	for (int i = 1; i < row; i++)
	{
		for (int j = 1; j < column; j++)
		{
			if (str1[i - 1] == str2[j - 1])
			{
				martix[i][j] = martix[i - 1][j - 1] + 1;
			}
			else
			{
				martix[i][j] = martix[i - 1][j] > martix[i][j - 1] ?
					martix[i - 1][j] : martix[i][j - 1];
			}
		}
	}
	value = row + column - 2 - 2 * martix[row - 1][column - 1];
	for (int i = 0; i < row; i++)
	{
		delete [] martix[i];
	}
	delete [] martix;
	return value;
}

int main()
{
	string str1, str2;
	while (cin >> str1 >> str2)
		cout << fun(str1, str2) << endl;
	return 0;
}
	int row = str1.length()+1;
	int column = str2.length()+1;
	int value;
	int ** martix = new int * [row];
	for (int i = 0; i < row; i++)
	{
		martix[i] = new int [column];
	}


	for (int i = 0; i < row; i++)
	{
		martix[i][0] = 0;
	}
	for (int j = 0; j < column; j++)
	{
		martix[0][j] = 0;
	}


	for (int i = 1; i < row; i++)
	{
		for (int j = 1; j < column; j++)
		{
			if (str1[i - 1] == str2[j - 1])
			{
				martix[i][j] = martix[i - 1][j - 1] + 1;
			}
			else
			{
				martix[i][j] = martix[i - 1][j] > martix[i][j - 1] ?
					martix[i - 1][j] : martix[i][j - 1];
			}
		}
	}
	value = row + column - 2 - 2 * martix[row - 1][column - 1];
	for (int i = 0; i < row; i++)
	{
		delete [] martix[i];
	}
	delete [] martix;
	return value;
}

int main()
{
	string str1, str2;
	while (cin >> str1 >> str2)
		cout << fun(str1, str2) << endl;
	return 0;
}

3. 最小公倍数

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=600&&ExamID=595

问题分析:

分解m的质因数,全部属于给定数列,即为Possible。

解答:

#include <iostream>
#include <cmath>
#include <vector>

using namespace std;

struct myStruct
{
	long factor;
	int exponent;
};

bool fun(long * array, long n, long m)
{
	if (n <= 0 || m <= 0)
		return false;
	vector <myStruct> primes;
	// 本不想用temp变量,但在线编译器不支持myStruct{i, exponent}的格式
	myStruct temp;
	if (m == 1)
	{
		temp.factor = 1;
		temp.exponent = 1;
		primes.push_back(temp);
	}
	else
	{
		long key = (long)sqrt((double)m);
		long i, mp;
		for (i = 2, mp = m; i <= key; i++)
		{
			int exponent = 0;
			while (mp % i == 0)
			{
				exponent++;
				mp /= i;
			}
			if (exponent > 0)
			{
				temp.factor = i;
				temp.exponent = exponent;
				primes.push_back(temp);
			}
		}
		if (mp > key)
		{
			temp.factor = mp;
			temp.exponent = 1;
			primes.push_back(temp);
		}
	}


	for (long i = 0; i < n; i++)
	{
		if (m % array[i] != 0)
			continue;
		vector <myStruct> ::iterator it = primes.begin();
		while (it != primes.end())
		{
			if (array[i] % (long)pow((double)(it->factor), it->exponent) == 0)
				it = primes.erase(it);
			else
				++it;
		}
		if (primes.empty())
			break;
	}
	if (primes.empty())
		return true;
	else
	{
		primes.clear();
		return false;
	}
}

int main()
{
	long n, m;
	long * array;
	while (cin >> n >> m)
	{
		array = new long[n];
		for (long i = 0; i < n; i++)
		{
			cin >> array[i];
		}
		if (fun(array, n, m))
			cout << "Possible" << endl;
		else
			cout << "Impossible" << endl;
		delete[] array;
	}
	return 0;
}
	long factor;
	int exponent;
};

bool fun(long * array, long n, long m)
{
	if (n <= 0 || m <= 0)
		return false;
	vector <myStruct> primes;
	// 本不想用temp变量,但在线编译器不支持myStruct{i, exponent}的格式
	myStruct temp;
	if (m == 1)
	{
		temp.factor = 1;
		temp.exponent = 1;
		primes.push_back(temp);
	}
	else
	{
		long key = (long)sqrt((double)m);
		long i, mp;
		for (i = 2, mp = m; i <= key; i++)
		{
			int exponent = 0;
			while (mp % i == 0)
			{
				exponent++;
				mp /= i;
			}
			if (exponent > 0)
			{
				temp.factor = i;
				temp.exponent = exponent;
				primes.push_back(temp);
			}
		}
		if (mp > key)
		{
			temp.factor = mp;
			temp.exponent = 1;
			primes.push_back(temp);
		}
	}


	for (long i = 0; i < n; i++)
	{
		if (m % array[i] != 0)
			continue;
		vector <myStruct> ::iterator it = primes.begin();
		while (it != primes.end())
		{
			if (array[i] % (long)pow((double)(it->factor), it->exponent) == 0)
				it = primes.erase(it);
			else
				++it;
		}
		if (primes.empty())
			break;
	}
	if (primes.empty())
		return true;
	else
	{
		primes.clear();
		return false;
	}
}

int main()
{
	long n, m;
	long * array;
	while (cin >> n >> m)
	{
		array = new long[n];
		for (long i = 0; i < n; i++)
		{
			cin >> array[i];
		}
		if (fun(array, n, m))
			cout << "Possible" << endl;
		else
			cout << "Impossible" << endl;
		delete[] array;
	}
	return 0;
}
 

4. F(X)

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=519&&ExamID=514

问题分析:

读懂题目,此题就不难了。

将n分解质因数,再将质因数组合为2组即可。

对于合数,其相同的k个质因数,不完全分成2有序组的方法共(k+1)(k+2)/2种,所有质因数的分法相简乘,为解。
对于质数,显然F(x)==3。

解答:

#include <iostream>
#include <cmath>

using namespace std;

long long fun(long long n)
{
	if (n <= 0)
		return 0;
	if (n == 1)
		return 1;
	long long number;
	long long all = 1;
	long long threshold = (long long)ceil(sqrt((double)n));
	for (long long i = 2; i <= threshold; i++)
	{
		number = 0;
		while (n % i == 0)
		{
			number++;
			n /= i;
		}
		if (number > 0)
			all *= (number + 1)*(number + 2) / 2;
		if (i > n)
			break;
	}
	if (n > 1)
		all *= 3;
	return all;
}

int main()
{
	long long n;
	while (cin >> n)
	{
		cout << fun(n) << endl;
	}
	return 0;
}
	if (n <= 0)
		return 0;
	if (n == 1)
		return 1;
	long long number;
	long long all = 1;
	long long threshold = (long long)ceil(sqrt((double)n));
	for (long long i = 2; i <= threshold; i++)
	{
		number = 0;
		while (n % i == 0)
		{
			number++;
			n /= i;
		}
		if (number > 0)
			all *= (number + 1)*(number + 2) / 2;
		if (i > n)
			break;
	}
	if (n > 1)
		all *= 3;
	return all;
}

int main()
{
	long long n;
	while (cin >> n)
	{
		cout << fun(n) << endl;
	}
	return 0;
}
 

5. -3+1

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=503&&ExamID=498

问题分析:

这个题目让我想起拼烟头问题。

将全部数字除以3取余数,商即为需要+1的个数。然后把这些+1分别安插在数字中。

余数为0的,忽略;余数为2的,+1后可再次-3变为0,操作数+1;余数为1的,两次+1后可再次-3变为0;最后加上剩余的+1可完成的操作数。

解答:

#include <iostream>

using namespace std;

unsigned long long fun(unsigned long * array, unsigned int n)
{
	unsigned long long var = 0ul;
	unsigned long long all = 0ul;

	for (unsigned int i = 0; i < n; i++)
	{
		var += array[i] / 3;
		array[i] %= 3;
	}
	if (var == 0)
		return 0;
	all = var;
	for (unsigned int i = 0; i < n; i++)
	{
		if (array[i] == 2)
		{
			if (var > 1)
				all++;
		}
		else if (array[i] == 1)
		{
			if (var > 1)
			{
				var--;
				all++;
			}
		}
	}
	all += (var+1)/2-1;
	return all;
}

int main()
{
	unsigned int n;
	unsigned long * array;
	while (cin >> n)
	{
		array = new unsigned long [n];
		for (unsigned int i = 0; i < n; i++)
		{
			cin >> array[i];
		}
		cout << fun(array, n) << endl;
		delete[] array;
	}
	return 0;
}
	unsigned long long var = 0ul;
	unsigned long long all = 0ul;

	for (unsigned int i = 0; i < n; i++)
	{
		var += array[i] / 3;
		array[i] %= 3;
	}
	if (var == 0)
		return 0;
	all = var;
	for (unsigned int i = 0; i < n; i++)
	{
		if (array[i] == 2)
		{
			if (var > 1)
				all++;
		}
		else if (array[i] == 1)
		{
			if (var > 1)
			{
				var--;
				all++;
			}
		}
	}
	all += (var+1)/2-1;
	return all;
}

int main()
{
	unsigned int n;
	unsigned long * array;
	while (cin >> n)
	{
		array = new unsigned long [n];
		for (unsigned int i = 0; i < n; i++)
		{
			cin >> array[i];
		}
		cout << fun(array, n) << endl;
		delete[] array;
	}
	return 0;
}

6. An easy problem

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=500&&ExamID=495

问题分析:

先把题目的数学语言翻译成人话:
对于给定的非负整数n和m,求正整数c满足:
(1)对任两个非负整数x和y, 必存在一个极小正实数ε0,使得 |n*x+m*y-c|>ε0.
(2)对任一非负整数d,且d>c,必存在两个非负整数x'和y',使得对任一极小正实数ε,均有|n*x'+m*y'-d|<ε.
其中,n和m的最大公约数为1,以上整数均在64位二进制数以内。
再好理解一点:
对于给定的非负整数n和m,求正整数c满足:
(1)无论多少个n和m,都累加不出c来.
(2)所有比c大的数,都能用n和m累加出来
其中,n和m的最大公约数为1,以上整数均在64位二进制数以内。
两个互质数,通过不限次数的加减计算,可以得出所有整数

解答:

#include <iostream>

using namespace std;

long long fun(long long n, long long m)
{
	if (n <= 1 || m <= 1)
		return 0;
	return n*m-n-m;
}

int main()
{
	long long n, m;
	long long c;
	while (cin >> n >> m)
	{
		c = fun(n, m);
		if (c > 0)
		{
			cout << c << endl;
		}
		else
		{
			cout << "impossible." << endl;
		}
	}
	return 0;
}
	if (n <= 1 || m <= 1)
		return 0;
	return n*m-n-m;
}

int main()
{
	long long n, m;
	long long c;
	while (cin >> n >> m)
	{
		c = fun(n, m);
		if (c > 0)
		{
			cout << c << endl;
		}
		else
		{
			cout << "impossible." << endl;
		}
	}
	return 0;
}

7. 第五届在线编程大赛月赛第三题:石子游戏(1)

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=617&&ExamID=612

问题分析:

1.所有数以二进制按位异或求和
2.对于异或和为0的数组,无论下一手如何取,
  结果都使异或和不为0,或不能取(失败)
3.对于异或和不为0的数组,一定存取某取法,
  使得异或和变为0。如下:
  对于非0的32位无符号整数A,其填位补码
  B = -(0xFFFFFFFF | A),
  如果数组中最大数==A,则此数减去A后,异或和重置为0;
  如果数组中最大数!=A,则此数减去B后,异或和重置为0
4.结论:异或和非0必胜,否则必败

解答:

#include <iostream>
#include <cmath>

using namespace std;

bool win(unsigned long * var, unsigned int n)
{
	unsigned long a = 0ul;
	for (unsigned int i = 0; i < n; i++)
	{
		a ^= var[i];
	}
	if (a == 0ul)
		return false;
	else
		return true;
}

int main()
{
	unsigned int n;
	while (cin >> n)
	{
		unsigned long * stones = new unsigned long [n];
		for (unsigned int i = 0; i < n; i++)
		{
			cin >> stones[i];
		}
		if (win(stones, n))
			cout << "Win" << endl;
		else
			cout << "Lost" << endl;
		delete[] stones;
	}
	return 0;
}
	unsigned long a = 0ul;
	for (unsigned int i = 0; i < n; i++)
	{
		a ^= var[i];
	}
	if (a == 0ul)
		return false;
	else
		return true;
}

int main()
{
	unsigned int n;
	while (cin >> n)
	{
		unsigned long * stones = new unsigned long [n];
		for (unsigned int i = 0; i < n; i++)
		{
			cin >> stones[i];
		}
		if (win(stones, n))
			cout << "Win" << endl;
		else
			cout << "Lost" << endl;
		delete[] stones;
	}
	return 0;
}

8. 第五届在线编程大赛月赛第一题:完全平方数的个数

问题描述:

http://hero.youkuaiyun.com/Question/Details?ID=608&&ExamID=603

问题分析:

这道题目是给初中生玩的吧?a和b开平方,取中间整数个数,结束。

解答:

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    int a, b;
    int n;

    //输入数据
    while (cin >> a >> b)
    {
        float a1 = sqrt((float)a);
        float b1 = sqrt((float)b);
        a = (int) ceil(a1);
        b = (int) floor(b1);
        n = b >= a ? b-a+1 : 0;
        cout << n << endl;
    }
    return 0;
}

全部内容原创,转载请注明出处!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值