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

https://lutece.xyz/contest/detail/10/

不知道英文场的题面是否合各位大爷口味呢?

A

source: Pxt

k>=n时,耗时即为步骤m*每步时间t

k

#include 
using namespace std;

int main (void) {
	int n, m, k, t;
	scanf("%d%d%d%d", &n, &m, &k, &t);
	printf("%d\n", t * (n > k ? n * m / k + (n * m % k != 0) : m));
}

B

source: SAuppp

显然N是偶数的时候
printf N / 2 (可以一直减去2这个最小因子 然后得到另外一个偶数
当N是奇数 他的最小因子一定是奇数 (质数就一个偶数2,其他全是奇数
然后作差得到偶数 然后就成了第一种情况

至于怎么找一个数的最小因子

枚举2 到 sqrt N 即可 若果一个因子都没有 那这个数一定是质数 printf 1

所以枚举大概1e6次即可

#include 
#include 
long long N,sqr;
int main () {
	scanf("%lld",&N);
	sqr = sqrt(N) + 0.5;
	if(N & 1) {
        for(int i = 3;i <= sqr;++i) {
			if(N % i == 0) {
				printf("%lld\n",(N - i) / 2 + 1);
				return 0;
			}
        }
        printf("1\n");
	}
	else printf("%lld\n",N / 2);
}


C

source: moeis

题意:给n个长度为k的01串,求一个与n个串差异度的最大值最小的串。差异度即A异或B后1的个数。

n最大100,k最大15,因此暴力枚举即可。要求字典序最小,所以直接从小到大枚举0到 2 k 2^k 2k 内所有数然后与n个串求差异度的最大值,再从最大值中选出最小值即可。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int inf=1e8;
const int N=1e2+3;
int n,k,a[N];
string s;
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
    	cin>>s;
    	for(int j=s.length()-1;j>=0;j--) a[i]+=(s[j]=='1')?(1<<(k-j-1)):0;
    }
	int ans=0,tot=inf;
	for(int i=0;i<(1<<k);i++){
		int res=-1;
		for(int j=1;j<=n;j++){
			int x=i^a[j],cnt=0;
			for(int z=0;z<k;z++) if(x&(1<<z)) cnt++;
			res=max(res,cnt);
		}
		if(tot>res){
			tot=res;
			ans=i;
		}
	}
	for(int i=0;i<k;i++) printf("%d",(ans&(1<<(k-i-1)))?1:0);
    return 0;
}

顺带一提master oy就是在第一场正式赛装备暴击猫那位大人(逃

D

source:qhqh

首先排坑:

小坑:金币是没有用的。

中坑:因为Magic Flower的缘故,猛男每爬一层塔回复6点生命值。如果不知道这一点是无法理解样例2的。

大坑:猛男的生命值不可能达到其上限。(过了题的同学想想为什么这个是个坑,如果你写了if (hp > 1000000) hp = 1000000,说明你可能并没有考虑完全。如果这道题生命值上限可以达到,你的想法还是对的吗?)

看到本题可能会想到的方法是枚举猛男应该在哪一层使用烟雾弹,但是这样做很明显是不优的。我们比较容易想到,在遇见除boss之外最强的怪物时使用烟雾弹能够最大程度避免生命值下降(可以把烟雾弹当作一瓶hp回复药,当你不得不使用时,肯定希望它能回复最多的生命值,它回复的生命值就是之前遇到的最强怪物对猛男造成的伤害值),但是可能在遇见这个最强怪物之前猛男就遇上了不得不使用烟雾弹的情形。综合这两点考虑,便可以得到一种解法。

有兴趣的同学可以思考两个问题。把生命值上限改为100000,这题怎么做?把烟雾弹数量改为多个,这题怎么做?

#include 
using namespace std;

int main (void) {
	int m, n, val;
	scanf("%d%d", &m, &n);

	int hp = m;
	int maxn = 0;
	bool used = false;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &val);
		if (i != n) maxn = max(maxn, val);
		if (hp - val <= 0) {
			if (used || hp + maxn - val <= 0) {
				printf("NO\n");
				return 0;
			} else {
				used = true;
				hp += maxn;
			}
		}
		hp = hp - val + 6;
	}
	printf("YES\n");
	return 0;
}

PS:关于上面生命值上限的问题,补充一组栗子:

(生命值上限设为20)
20 4
10 5 9 18

猛男在第三层使用烟雾弹才能通关。

E

source: ZXY

k k k个人的最大公约数自然就是这 k k k个人中每个人魅力值因数分解后,因数的个数满足   c n t ≥ k \ cnt\geq k  cntk的最大因数,所以我们每次将魅力值进行分解因数的操作,最后遍历一遍可能的因数即可。

#include 
using namespace std;

const int MAXN = 1e5 + 10;

int cnt[MAXN];

int main (void) {
	int n, val;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &val);
		int lim = sqrt(val);
		for (int i = 1; i <= lim; i++) {
			if (val % i == 0) {
				cnt[i]++;
				cnt[val / i]++;
			}
		}
		if (lim * lim == val) cnt[lim]--;
	}
	int cur = 1e5;
	for (int i = 1; i <= n; i++) {
		while (cnt[cur] < i) cur--;
		printf("%d\n", cur);
	}
}

你可能感兴趣的:(电子科技大学第十届ACM趣味程序设计竞赛第五场(正式赛)官方题解)