第二届“传智杯”全国大学生IT技能大赛(初赛) 解题报告

整体评价:比较简单的一套题,前三道题大致相当于Codeforces div 2的T1、T2难度,第四题在div 1的T1、T2难度之间。

难度排序:A < C < B < D

A: 软件工程实习

简单题,开个数组记录一下每位选手的分组和理论分数;然后分别计算每个队伍的项目得分。最后计算所有学生的分数并排序即可(可以用结构体捆绑分组和学生成绩)。注意需要四舍五入的细节。

#include
#include
#include
using namespace std;
	struct newdata
	{
		int score,type;
	};
	int n,k;
	newdata student[1001];
	int score2[27][27];
	int score3[27];
bool cmp(newdata i,newdata j)
{
	return (i.score < j.score || (i.score == j.score && i.type > j.type));
}
int main()
{
	scanf("%d%d",&n,&k);
	for (int i = 1;i <= n;i ++)
	{
		char c;
		scanf("%d %c",&student[i].score,&c);
		student[i].type = c - 'A' + 1;
	}
	for (int i = 1;i <= k;i ++)
		for (int j = 1;j <= k;j ++)
			scanf("%d",&score2[i][j]);
	for (int i = 1;i <= k;i ++)
	{
		int sum = 0;
		for (int j = 1;j <= k;j ++)
			sum += score2[j][i];
		double average = double(sum) / k;
		int delta = 0;
		for (int j = 1;j <= k;j ++)
			if (abs(average - score2[j][i]) > 15)
			{
				delta ++;
				sum -= score2[j][i];
			}
		score3[i] = round(double(sum) / (k - delta));
	}
	for (int i = 1;i <= n;i ++)
		student[i].score = round(student[i].score * 0.6 + score3[student[i].type] * 0.4);
	sort(student + 1,student + n + 1,cmp);
	for (int i = n;i >= 1;i --)
		printf("%d %c\n",student[i].score,char(student[i].type + 'A' - 1));
	return 0;
} 

B: 1024 程序员节发橙子

稍微有点思维难度,但不难发现,这本质就是一个动态规划的套路题。

讨论具体成绩数值是没有意义的,我们只需要从原数列看出它们对应的大小关系,于是很容易联想到类似于【合唱队形】这道经典题,即对于每个学生,我们取它连续上升序列和连续下降序列中的最大值即可。

据说有人想到差分约束系统,那就有点小题大做了。

#include
#include
using namespace std;
	int n;
	int a[1000002];
	long long dp[1000002];
	long long dp2[1000002];
int main()
{
	scanf("%d",&n);
	for (int i = 1;i <= n;i ++)
	{
		scanf("%d",&a[i]);
		if (a[i] > a[i - 1])
			dp[i] = dp[i - 1] + 1;
		else dp[i] = 1;
	}
	dp2[n] = 1;
	for (int i = n - 1;i >= 1;i --)
		if (a[i] > a[i + 1])
			dp2[i] = dp2[i + 1] + 1;
		else dp2[i] = 1;
	long long ans = 0;
	for (int i = 1;i <= n;i ++)
		ans += max(dp[i],dp2[i]);
	printf("%lld",ans);
	return 0;
}

C: 众数出现的次数

乍一看还以为要用位运算性质,似乎很难。但实际上就是道简单题,直接把所有可能的数存进数组中,排下序统计连续相同数的个数的最大值即可。

细节是要判断a和a xor b是否相同,因为这个WA一次。

#include
#include
using namespace std;
	int n,cnt;
	long long num[2000001];
int main()
{
	scanf("%d",&n);
	for (int i = 1;i <= n;i ++)
	{
		long long a;
		scanf("%lld",&a);
		num[++cnt] = a;
		long long b;
		scanf("%lld",&b);
		if (a != (a ^ b))
			num[++cnt] = a ^ b;
	}
	sort(num + 1,num + cnt + 1);
	int now = 1;
	long long ans = num[1];
	int tot = 1;
	for (int i = 2;i <= cnt;i ++)
		if (num[i] != num[i - 1])
		{
			if (now > tot)
			{
				tot = now;
				ans = num[i - 1];
			}
			now = 1;
		}
		else now ++;
	if (now > tot)
		ans = num[cnt];
	printf("%lld",ans);
	return 0;
}

D: 特殊的翻转

其实做完前三题我还有两个半小时多一点,但是第四题想复杂了最后放弃。

十六进制转二进制没什么好说,每一位对应四位后去掉前缀0。

后面的想法:做过很多翻硬币的题,加之前几天也看了一些关于奇偶性问题的资料,结果以为是要用数学方法。于是先考虑如何判断无解。想法是每个1可以左移或右移3位,于是考虑所有1是否都在3的倍数上。但是这种思路显然错误,因为在考虑多个1的反转时,不能简单地以单个1叠加。

后面看了题解才发现原来不是数学问题,就是单纯地贪心。容易发现选取每个中心点翻转两次后与没翻转是等价的,于是每个中心点最多翻转一次。那么只需要从左往右枚举所有中心点,如果中心点左边为1则翻转,否则不翻转即可。

特殊情况:由于首尾必定为1,要讨论第一次翻第一位还是第二位并取最小值,若都无解,则输出"No".

#include
#include
#include
#include
using namespace std;
	string s;
	bool t[4000001];
	bool a[4000001];
	int cnt,st;
int main()
{
	cin >> s;
	for (int i = 0;i < s.size();i ++)
		if (s[i] >= '0' && s[i] <= '9')
		{
			int k = s[i] - '0';
			for (int j = 3;j >= 0;j --)
				t[++cnt] = ((k >> j) & 1);
		}
		else
		{
			int k = s[i] - 'A' + 10;
			for (int j = 3;j >= 0;j --)
				t[++cnt] = ((k >> j) & 1);
		}
	for (int i = 1;i <= cnt;i ++)
		if (t[i])
		{
			st = i;
			break;
		}
	if (cnt - st + 1 <= 2)
	{
		if (st == cnt)
			printf("%d",t[st]);
		else if (t[st] ^ t[cnt])
			printf("No");
		else printf("%d",t[st]);
		return 0;
	}
	int sum = 1;
	for (int i = st;i <= cnt;i ++)
		a[i] = t[i];
	a[st] = 0;
	a[st + 1] ^= 1;
	for (int i = st + 1;i < cnt - 1;i ++)
		if (a[i])
		{
			sum ++;
			a[i] ^= 1;
			a[i + 1] ^= 1;
			a[i + 2] ^= 1;
		}
	if (a[cnt - 1] && a[cnt])
		sum ++;
	else if (a[cnt - 1] ^ a[cnt])
		sum = -1;
	int ans = sum;
	sum = 1;
	for (int i = st;i <= cnt;i ++)
		a[i] = t[i];
	a[st] = 0;
	a[st + 1] ^= 1;
	a[st + 2] ^= 1;
	for (int i = st + 1;i < cnt - 1;i ++)
		if (a[i])
		{
			sum ++;
			a[i] ^= 1;
			a[i + 1] ^= 1;
			a[i + 2] ^= 1;
		}
	if (a[cnt - 1] && a[cnt])
		sum ++;
	else if (a[cnt - 1] ^ a[cnt])
		sum = -1;
	if (ans == -1 && sum == -1)
		printf("No");
	else if (sum == -1)
		printf("%d",ans);
	else if (ans == -1)
		printf("%d",sum);
	else printf("%d",min(ans,sum));
	return 0;
}

最后排名25,三题榜首但没AK,有点可惜啊。

你可能感兴趣的:(随笔)