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

题解


第一题

令单次砸出第i个式神概率为 P i ( 0 ≤ P i ≤ 1 ) P_i (0 \leq P_i \leq 1) Pi(0Pi1), 则有
两次以内砸出的概率为
P i = P + ( 1 − P ) ∗ P P_i = P + (1 - P) * P Pi=P+(1P)P
于是有第i个式神砸出的期望为 P i P_i Pi
由于砸不同式神的事件之间互相独立,所以总期望简单地将式神相加即可。

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

double ans, in; int N;

int main()
{
	cin >> N;
	for(int i = 0;i < N; ++i)
	{
		scanf("%lf", &in); 
		in /= 100; 
		in = (1 - in) * in + in; 
		ans += in; 
	}
	printf("%.3lf\n", ans); 
	return 0;
}


第二题

多边形合法的条件是:最长边小于其他边之和。
换句话说,边长之和应该大于最长边的二倍。
于是记录一下当前最长的边和边长之和即可。

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

int N;
long long now, sum;
long long maxnow;

int main()
{
	cin >> N;
	for(int i = 0;i < N; ++i)
	{
		scanf("%lld", &now);
		sum += now;
		if(now > maxnow)
			maxnow = now;
		if(sum > 2 * maxnow)
		{
			printf("%d\n", i + 1);
			return 0;
		}
	}
	printf("-1\n");
	return 0;
}

第三题

暴力就好了。因为一次只能使得某个字母的次数减一,所以每个字母至少都被拿了它存在的次数那么多次。于是我们从需要拿的次数最多的开始拿,一直拿到全部拿完为止。

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

int N;int num[30];int ans;

void find(int pl, int here) // 从最高点开始向两侧拿
{
	int now = here;
	for(int i = pl;i >= 0; --i)
	{
		now = min(now, num[i]);
		num[i] -= now;
	}
	now = here;
	for(int i = pl + 1;i < 26; ++i)
	{
		now = min(now, num[i]);
		num[i] -= now;
	}
	return;
}

void solve()
{
	while(true)
	{
		int pl = -1, maxnum = -1;
		for(int i = 0;i < 26; ++i)
		{
			if(num[i] > maxnum)
			{
				maxnum = num[i];
				pl = i;
			}
		}
		if(maxnum == 0) // 拿完了就结束了
			break;
		else
		{
			ans += maxnum;
			find(pl, maxnum);
		}
	}
	cout << ans << endl;
	return;
}

int main()
{
	cin >> N; string str; cin >> str;
	for(int i = 0;i < str.length(); ++i)
		++num[str[i] - 'a'];
	solve();
	return 0;
}

第四题

模拟题。
就照着题意模拟就好了。要求有点多。但是思路应该挺清楚的。

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

int N, K;

int num[10];

int main()
{
	cin >> N >> K;
	for(int i = 1;i <= N; ++i)
	{
		string str;cin >> str;
		++num['F' - 'A'];
		if(num['F' - 'A'] == 50)
		{
			if(K >= i) printf("%d F\n", i);
			else printf("Feizhou Yin\n");
			return 0;
		}
		int len = str.length();
		for(int j = 0;j < len; ++j)
		{
			++num[str[j] - 'A'];
			if(num[str[j] - 'A'] == 50)
			{
				if(K >= i) printf("%d %c\n", i, str[j]);
				else printf("Feizhou Yin\n");
				return 0;
			}
		}
	}
	if(N < K) printf("AMNZ");
	else printf("Feizhou Yin\n");
	return 0;
}

第五题

可证:一个数随机打乱后形成的新数,与原数之差的绝对值必然是9的整数倍。

证明:

令初始数字为 X n X n − 1 . . . X 0 X_nX_{n-1}...X_0 XnXn1...X0
现在我们交换其中两个数位, X a X_a Xa X b X_b Xb
则两数之差为
( X a ∗ 1 0 a + X b ∗ 1 0 b ) − ( X b ∗ 1 0 a + X a ∗ 1 0 b ) (X_a * 10^a + X_b * 10^b) - (X_b * 10^a + X_a * 10^b) (Xa10a+Xb10b)(Xb10a+Xa10b)
= ( X a − X b ) ∗ 1 0 a + ( X b − X a ) ∗ 1 0 b = (X_a - X_b) * 10^a + (X_b - X_a) * 10^b =(XaXb)10a+(XbXa)10b
= ( X a − X b ) ∗ ( 1 0 a − 1 0 b ) = (X_a - X_b) * (10^a - 10^b) =(XaXb)(10a10b)
= ( X a − X b ) ∗ ( 1 0 ( a − b ) − 1 ) ∗ 1 0 b = (X_a - X_b) * (10^{(a - b)} - 1) * 10^b =(XaXb)(10(ab)1)10b
令(a > b),则 ( 1 0 ( a − b ) − 1 ) = 999...9 (10^{(a - b)} - 1) = 999...9 (10(ab)1)=999...9 (共 a − b a - b ab 个9),是9的整数倍( 9 ∗ 111...1 9 * 111...1 9111...1)。
于是互换两个数位后得到的数与原数的差值必然是9的整数倍。
任意互换数位后的数,必然可由有限次两个数位互换得到。
于是前述命题得证。

于是问题转化为如何用当前的数字任意排列,得到最小的数。
显然,较大的数位上的数字应该尽可能小。于是对数位上的数字进行排序,小的在前大的在后即可。

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

const int MAXN = 1000 + 10;
char ss[MAXN];

int main()
{
	scanf("%s", ss);
	int len = strlen(ss);
	sort(ss, ss + len);
	printf("%s", ss);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值