电子科技大学第十届ACM趣味程序设计竞赛第三场(正式赛)官方题解

网址:https://lutece.xyz/contest/detail/8/

A 秦皇炒饭

source: Pxt

偶数不满足两两互质,因此最少要分n/2组。相邻的两个数2k与2k+1一定互质可以分为1组,编号为1的可以加入任意组。

因此,$$ ans=\left\{ \begin{aligned} 1 && n=1 \\ n/2 && n>1 \end{aligned} \right. $$.

#include<cstdio>
using namespace std;
int i,n;
int main()
{
   scanf("%d",&n);
   if(n>1) n/=2;
   for(i=1;i<=n;++i) printf("Wed.Strong");
   return 0;
}

B 摩天乐

source: Range

对于输入在同一层的特判。如果一开始就在电梯范围,就直接到同一行再走。否则分左边下去和右边下去的情况,可以知道肯定是从$L$$R$的位置下去,所以两边都算一下取个最小值就行。

该题测试组数T最大值实际上为1000,这是我们的过失,在这里向开数组存数据导致RE的同学道个歉了。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;

long long n, m, l, r, a, b, c, d;
int main()
{
  int T; cin >> T;
  while (T--)
  {
    cin >> n >> m >> l >> r >> a >> b >> c >> d;
    if (a == c)
    {
      cout << abs(b-d) << endl;
      continue;
    }
    long long ans = 0;
    if (b <= l || b >= r)
    {
      ans = abs(a-c) + abs(b-d);
    }
    else
    {
      long long cost1 = b-l+abs(d-l)+abs(a-c);
      long long cost2 = r-b+abs(r-d)+abs(a-c);
      ans = min(cost1, cost2);
    }
    cout << ans << endl;
  }
  return 0;
}

C Akane

source: meltout

记录%m余0,1,2,....m-1的元素个数

重排列后尽量使余数和为m的元素相邻,假设两者个数分别为a,b,若a=b,则最多只能构成a$\times$2-1对,否则,可以通过将个数更多的元素放在外围,构造min(a,b)$\times$2对

特别地,%m余0的元素可以不计顺序直接放在一起,假设元素个数为a,可构成a-1对

若m为偶数,则%m余m/2的元素也可以直接放在一起,对答案贡献同上

需要注意a=0时特判,以免对答案做负贡献
 

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxN=1e6+5;

int a[maxN];

int main()
{
    int k,n,m,x;
    scanf("%d%d",&n,&m);
    for(k=0;k<n;k++)
    {
        scanf("%d",&x);
        a[x%m]++;
    }
    int ans=max(0,a[0]-1);
    for(k=1;k<(m+1)/2;k++)
    {
        ans+=min(a[k],a[m-k])*2;
        if(a[k]==a[m-k] && a[k]!=0)ans--;
    }
    if(m%2==0)ans+=max(0,a[m/2]-1);
    printf("%d",ans);
    return 0;
}

 

D 强哥打电话

source: zhsq11, forgottencsc

注意到情侣队友打电话的时间是顺序给出的,所以顺序检查即可。

题目要求情侣队友的电话时间是左闭右开的,也就是说挂下电话的一瞬间是可以打通电话的。

因此暴力检查一下每段强哥打电话的区间能不能打通就行了。

关于这个时间表示法的处理办法:可以写一个将给出的时间转换成秒数的函数,这样就比较好进行处理了。

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

const int Time_Max = 24 * 60 * 60; 
const int MAXN = 100 + 10;
int From[MAXN], To[MAXN]; int N;
int Qiang_Time, Qiang_Interval, Qiang_Wait;

int Time_Conversion()
{
	int hour, min, sec;
	scanf("%d:%d:%d", &hour, &min, &sec);
	return hour * 60 * 60 + min * 60 + sec;
}

void output(int seconds)
{
	int hour = seconds / (60 * 60);
	int min = (seconds - hour * (60 * 60)) / 60;
	int sec = seconds - hour * (60 * 60) - min * 60;
	if(seconds >= Time_Max)
		printf("-1\n");
	else
		printf("%02d:%02d:%02d\n", hour, min, sec);
	exit(0);
}

void read()
{
	cin >> N;
	int h1, m1, s1, h2, m2, s2;
	for(int i = 0;i < N; ++i)
	{
		From[i] = Time_Conversion();
		To[i] = Time_Conversion();
	}
	Qiang_Time = Time_Conversion();
	Qiang_Interval = Time_Conversion();
	Qiang_Wait = Time_Conversion();
	return;
}

void find()
{
	for(int i = 0;i < N; ++i)
	{	
		while(Qiang_Time <= To[i])
		{
			if(Qiang_Time < From[i])
				output(Qiang_Time);
			if(Qiang_Time + Qiang_Wait >= To[i])
				output(To[i]);
			Qiang_Time += Qiang_Interval;
		}
	}
	output(Qiang_Time);
	return;
}

int main()
{
	read(); find();
	return 0;
}

E  暴击猫

source: moe

$f[i][j]$表示第j次攻击前有i 层buff的概率,在无限次攻击后i将会无意义,也就是说$f[i]$会收敛。所以用$f[i]$表示无限次数攻击后有i层buff的概率。$f[0]$显然为p,$f[1]$为p*(1-p),以此类推,$f[n-1]=p*(1-p)^{n-1}$ 。注意因为有buff层数上限所以$f[n]=(f[n-1]+f[n])*(1-p)$,解得$f[n]=(1-p)^n$ 。剩下的就是算期望再作比了。

另解,直接暴力模拟,用随机函数来随机是否暴击然后模拟过程,算出两种总伤害然后作比。

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

int main()
{
	double p, k, a;
	int n;
	scanf("%lf%lf%lf%d", &p, &k, &a, &n);
	double init = p * k + (1 - p) * 100;
	double res = 0, base = p;
	for (int i = 1; i <= n; i++)
	{
		res += base * (k + a * (i - 1)) * p;
		base = base * (1 - p);
	}
	res += base * (k + n * a);
	res += (1 - p) * 100;
	printf("%.3lf", res / init);
	return 0;
}

 

 

没有更多推荐了,返回首页