ZZULI23级新生C语言周赛(5)——E,F,G

原题链接

E

题意很容易理解,给你处于同一天的两个时间,如果第一个时间比第二个时间早,输出YES,否则输出NO

C o d e Code Code

#include <stdio.h>

int main() {
	int h1, m1, s1;
	int h2, m2, s2;
	
	// 阿七发视频的时间
	scanf("%d%d%d", &h1, &m1, &s1);
	// 小赖狗发视频的时间
	scanf("%d%d%d", &h2, &m2, &s2);
	
	int time1 = h1 * 3600 + m1 * 60 + s1;
	int time2 = h2 * 3600 + m2 * 60 + s2;
	
	// 如果小赖狗发视频的时间 time2 比阿七发视频的时间 time1 晚
	// 那么能在小赖狗视频中看见阿七的视频
	if (time2 > time1) {
		puts("YES");
	} else {
		puts("NO");
	}
	return 0;
}

F

计算第 a a a 页到第 b 页之间所有页码对应的数字的长度的和即可,可以直接无脑枚举所有情况。

#include <stdio.h>

int a, b;
int cnt; // 蒙面人出的题的答案
int cnt_mxt; // mxt算出的答案

int main() {
	scanf("%d%d%d", &a, &b, &cnt_mxt);
	
	for (int i = a; i <= b; i ++) {
		if (i <= 9) { // 数字1~9中,每个数字的长度都是1
			cnt ++;
		} else if (i <= 99) { // 数字10~99中,每个数字的长度都是2
			cnt += 2;
		} else if (i <= 999) { // 数字100~999中,每个数字的长度都是3
			cnt += 3;
		} else if (i <= 9999) { // 数字1000~9999中,每个数字的长度都是4
			cnt += 4;
		} else if (i <= 99999) { // 数字10000~99999中,每个数字的长度都是5
			cnt += 5;
		} else if (i <= 999999) { // 数字100000~999999中,每个数字的长度都是6
			cnt += 6;
		} else if (i <= 9999999) { // 数字1000000~9999999中,每个数字的长度都是7
			cnt += 7;
		} else { // 数字10000000~99999999中,每个数字的长度都是8
			cnt += 8;
		}
	}
	
	// 如果两个答案一致,那么mxt就做对了
	if (cnt == cnt_mxt) {
		puts("nizhenlihai!");
	} else {
		puts("laji");
	}
	return 0;
}

虽然这个题很简单,但其实改编自一道经典的数位统计DP,原题目如下:

给你两个整数 a a a b b b,求 a a a b b b 之间所有数字中 0 0 0 ~ 9 9 9 各自的出现次数。

例如, a = 1024 a = 1024 a=1024 b = 1032 b = 1032 b=1032,则 a a a b b b 之间共有 9 9 9 个数如下:

1024 1025 1026 1027 1028 1029 1030 1031 1032

其中 0 出现 10 10 10 次,1 出现 10 10 10 次,2 出现 7 7 7 次,3 出现 3 3 3 次等等…

输入格式

输入包含多组测试数据。

每组测试数据占一行,包含两个整数 a a a b b b。其中 0   <   a , b   <   100000000 0~<~a,b~<~100000000 0 < a,b < 100000000

当读入一行为 0 0 时,表示输入终止,且该行不作处理。

输出格式

每组数据输出一个结果,每个结果占一行。

每个结果包含十个用空格隔开的数字,第一个数字表示 0 出现的次数,第二个数字表示 1 出现的次数,以此类推。

C o d e Code Code

#include <stdio.h>

int count(int n, int i) { // 1 ~ n 中数字 i 出现的次数
	int sum = 0;
	// 循环中每一次sum都加上满足0 <= xxxiyyy <= abcdefg的xxxiyyy的个数
	for (int base = 1; base <= n; base *= 10) {
		// 1 xxx <= abc - 1
		sum += (n / (base * 10) - (i == 0)) * base;
		// 2 xxx == abc
		if (n / base % 10 > i) // 2.1 d > i
			sum += base;
		if (n / base % 10 == i) // 2.2 d == i
			sum += n % base + 1;
	}
	return sum;
}

int main() {
	int a, b;
	while (scanf("%d%d", &a, &b), a || b) {
		if (a < b) {
			int t = a; a = b; b = t;
		}
		for (int i = 0; i <= 9; i ++) {
            printf("%d ", count(a, i) - count(b - 1, i));
		}
		puts("");
	}

	return 0;
}

G

题意:

给你两个由小写字母组成的字符串 s , t s, t s,t, 它们的长度相等。规定 s s s t t t 的“差异度”为它们具有不同字符的位置数。你可以交换 s s s 中的两个字符(不交换也可以),使得 s s s t t t 的“差异度”最小,并输出这个最小值。

思路:

我们最多可以交换依次 s s s 中的两个字符。很明显,交换一次字符会对二者的差异度产生以下影响:

  1. 差异度减小 2 2 2
  2. 差异度减小 1 1 1
  3. 差异度不变

计算好初始状态 s s s t t t 的差异度后,我们先判断是否存在情况1,因为这种情况可以使差异度减小 2 2 2,如果不存在 情况1,我们再判断是否存在 情况2情况3 无需判断,因为它不能改变差异度。

  1. 判断 情况1 的存在性

    假设交换了 s i , s j s_i,s_j sisj i < j i < j i<j)使得差异度减小了 2 2 2,那么很容易知道交换前 s , t s,t st 满足: s i   ! =   t i s_i~!=~t_i si != ti s j   ! =   t j s_j~!=~t_j sj != tj s i   =   t j s_i~=~t_j si = tj s j   =   t i s_j~=~t_i sj = ti

    我们可以选择遍历 s s s ,如果 s j   ! =   t j s_j~!=~t_j sj != tj,我们判断之前遍历过程中有没有遇见一个下标 i i i,满足 s i   =   t j s_i~=~t_j si = tj s j   = t i   s_j~=t_i~ sj =ti 

  2. 判断 情况2 的存在性

    情况1 类似,假设交换了 s i , s j s_i,s_j sisj i < j i < j i<j)使得差异度减小了 1 1 1,那么存在以下两种情况(在 s i   ! =   t i s_i~!=~t_i si != ti s j   ! =   t j s_j~!=~t_j sj != tj 条件下):

    1. t i   =   s j t_i~=~s_j ti = sj,即交换 s i , s j s_i, s_j si,sj 之后,使得 s i   =   t i s_i~=~t_i si = ti
    2. s i   =   t j s_i~=~t_j si = tj,即交换 s i , s j s_i, s_j si,sj 之后,使得 s j   =   t j s_j~=~t_j sj = tj

C o d e Code Code

#include <stdio.h>

int n;
char s[200010];
char t[200010];

int main() {
	scanf("%d", &n);
	scanf("%s%s", s + 1, t + 1);
	
	// res:s没有交换字符时两个字符串的“差异度”
	int res = 0;
	for (int i = 1; i <= n; i ++) {
		if (s[i] != t[i]) {
			res ++;
		}
	}
	
	// 情况1,判断是否存在一种交换方式,使得res减小2
	int exist[27][27] = {0};
	for (int i = 1; i <= n; i ++) {
		if (s[i] != t[i]) {
			int pos_s = s[i] - 'a' + 1;
			int pos_t = t[i] - 'a' + 1;
			if (exist[pos_t][pos_s]) {
				printf("%d\n", res - 2);
				return 0;
			}
			// 因为s[i]!=t[i],所以标记此时s[i]与t[i]的组合
			exist[pos_s][pos_t] = i;
		}
	}
	
	// 情况2,判断是否存在一种交换方式,使得res减小1
	int exist1[27] = {0};
	int exist2[27] = {0};
	for (int i = 1; i <= n; i ++) {
		if (s[i] != t[i]) {
			int pos_s = s[i] - 'a' + 1;
			int pos_t = t[i] - 'a' + 1;
			if (exist1[pos_s]) { // 情况2.1
				printf("%d\n", res - 1);
				return 0;
			}
			if (exist2[pos_t]) { // 情况2.2
				printf("%d\n", res - 1);
				return 0;
			}
			exist1[pos_t] = i;
			exist2[pos_s] = i;
		}
	}
	
	printf("%d\n", res); // 情况1和情况2都不存在
	return 0;
}
  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值