1001 害死人不偿命的(3n+1)猜想
卡拉兹(Callatz)猜想:
对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在 1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过 1000 的正整数 n,简单地数一下,需要多少步(砍几下)才能得到 n=1?
- 输入格式:
每个测试输入包含 1 个测试用例,即给出正整数 n 的值。
- 输出格式:
输出从 n 计算到 1 需要的步数。
- 输入样例:
3
- 输出样例:
5
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB
- 解析
没什么难点就是简单的按步骤来写判断语句
- 代码如下
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
int main(){
int n;
scanf("%d",&n);
int count = 0;
while(n!=1){
if(n%2==0){
n/=2;
}else{
n=(3*n+1)/2;
}
count++;//用来统计计算的次数
}
printf("%d",count);
return 0;
}
1002 写出这个数
读入一个正整数 n,计算其各位数字之和,用汉语拼音写出和的每一位数字。
- 输入格式:
每个测试输入包含 1 个测试用例,即给出自然数 n 的值。这里保证 n 小于 10 的100次方
- 输出格式:
在一行内输出 n 的各位数字之和的每一位,拼音数字间有 1 空格,但一行中最后一个拼音数字后没有空格。
- 输入样例:
1234567890987654321123456789
- 输出样例:
yi san wu
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB
-
解析
-
首先要计算出来输入的数字的每位之和,利用字符数组来实现
char input[1000];
int sum = 0;
// 读取输入
scanf("%s", input);
// 计算各位数字之和
for (int i = 0; input[i] != '\0'; i++) {
sum += input[i] - '0';
}
//input[i] != '\0':这是循环继续的条件。在 C 语言中,字符串以空字符 '\0' 作为结束标志,所以只要当前索引 i 对应的字符不是空字符,循环就会继续执行。
//input[i] - '0':通过将当前字符减去字符 '0',可以将字符转换为对应的整数。比如,如果 input[i] 是 '3',其 ASCII 码值为 51,'0' 的 ASCII 码值为 48,那么 '3' - '0' 就等于 3。
// 输出各位数字之和的拼音
- 然后是实现用汉字来代表0-9的数字
const char *pinyin[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
- 最后是要实现从首位开始实现数字与对应汉字的一一对应,先进后出我们想到用栈来实现即递归
void printDigitPinyin(int num) {
if (num / 10 > 0) {
printDigitPinyin(num / 10);
printf(" ");
}
printf("%s", pinyin[num % 10]);
}
完整代码如下
#include <stdio.h>
// 定义数字对应的拼音数组
const char *pinyin[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
// 递归输出数字各位的拼音
void printDigitPinyin(int num) {
if (num / 10 > 0) {
printDigitPinyin(num / 10);
printf(" ");
}
printf("%s", pinyin[num % 10]);
}
//代码执行流程
//假设 num 的值为 123,代码的执行流程如下:
//初始调用 printDigitPinyin(123),由于 123 / 10 = 12 > 0,会递归调用 printDigitPinyin(12)。
//在 printDigitPinyin(12) 中,因为 12 / 10 = 1 > 0,会递归调用 printDigitPinyin(1)。
//在 printDigitPinyin(1) 中,1 / 10 = 0,不满足递归条件,直接输出 pinyin[1 % 10],即 "yi"。
//回到 printDigitPinyin(12),在递归调用返回后,输出一个空格,然后输出 pinyin[12 % 10],即 "er"。
//回到 printDigitPinyin(123),在递归调用返回后,输出一个空格,然后输出 pinyin[123 % 10],即 "san"。
//最终输出结果为 "yi er san"。
int main() {
char input[1000];
int sum = 0;
// 读取输入
scanf("%s", input);
// 计算各位数字之和
for (int i = 0; input[i] != '\0'; i++) {
sum += input[i] - '0';
}
//input[i] != '\0':这是循环继续的条件。在 C 语言中,字符串以空字符 '\0' 作为结束标志,所以只要当前索引 i 对应的字符不是空字符,循环就会继续执行。
//input[i] - '0':通过将当前字符减去字符 '0',可以将字符转换为对应的整数。比如,如果 input[i] 是 '3',其 ASCII 码值为 51,'0' 的 ASCII 码值为 48,那么 '3' - '0' 就等于 3。
// 输出各位数字之和的拼音
printDigitPinyin(sum);
printf("\n");
return 0;
}
1003 我要通过!
“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 ——只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
字符串中必须仅有 P、 A、 T这三种字符,不可以包含其它字符; 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x或者是空字符串,或者是仅由字母 A 组成的字符串; 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c均或者是空字符串,或者是仅由字母 A 组成的字符串。 现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
- 输入格式:
每个测试输入包含 1 个测试用例。第 1 行给出一个正整数 n (≤10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。
- 输出格式:
每个字符串的检测结果占一行,如果该字符串可以获得“答案正确”,则输出 YES,否则输出 NO。
- 输入样例:
10
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
APT
APATTAA
- 输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
NO
NO
代码长度限制 16 KB
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB
- 解析
这个题目在分析层面需要费点功夫
首先要读懂题目的要求
1. 判断字符串中是否仅有 ‘P’,‘A’, 'T’这三种字符,包含其他字符就错误
这个条件实现
这个条件实现比较简单,不赘述
2. 任意形如 xPATx 的字符串都可以获得“答案正确”,其中 x 或者是空字符串,或者是仅由字符’A’组成的字符串;
这里的意思是中间有一个A两边有对等的A或者空格都可以
那么形如
PAT
APATA
AAPATAA
AAAPATAAA
都是满足条件的
下面主要是条件三很难理解
3. 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a、 b、 c 均或者是空字符串,或者是仅由字母 A 组成的字符串。
看到这个条件的话其实不知道在说什么
用示例中的正确来分析以下
(aPbTc)PAT
是正确的,此时a=" ",b="A",c=" "
那么把abc
代入(aPbATca)
中说明PAAT
是正确的,以此类推,若b = "AAAA......"
,a
与c
不变还是空格,那么PAAA.....T
依然是正确的
再举一个例子
(aPbTc)AAPATAA
对应a="AA",b="A",c="AA"
是正确的,那么代入到(aPbATca)
中,说明了对应AAPAATAAAA
是正确的,类推一下,我们发现,如果满足了
P
之前的A
的个数*P
之后和T
之前的个数=T
之后的个数,那么这个就是我们解题的关键
综上所述我们只需要满足三个最关键的东西
- 不能包含出PAT三个字母以外的字母
- 开头的’A’的个数 )乘以 (中间的’A’的个数) 等于(结尾的’A’的个数)
注意
如果开头和结尾为0个那么只要中间的个数不为0都成立,也满足上述的式子
完整代码如下
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
int judge(char *s) {
for(int j=0; s[j]!='\0'; j++) {
if(s[j]!='P'&&s[j]!='A'&&s[j]!='T') {
return 0;
}
}
int P = -1,T=-1;//这两个用来标记P和T 的位置
int len = strlen(s);//计算字符数组的长度
//先找到P和T 的位置
for(int i=0; i<len; i++) {
if(s[i]=='P') {
if(P!=-1) {
return 0;//说明出现了第二或者多个P,不满足情况
}
P = i;
} else if(s[i]=='T') {
if(T!=-1) {
return 0;
}
T=i;
}
}
if(P==-1||T==-1||P>=T-1) {
return 0; // 没有 'P' 或 'T',或者 'P' 在 'T' 之后,或者 'P' 和 'T' 相邻
}
int a = P;//开头的A的个数,注意不要-1,如果索引为4说明前面有0,1,2,3四个A
int b = T-P-1;//中间的A的个数
int c = len-T-1;//结尾的A的个数
return a*b==c;
}
int main() {
int n;
scanf("%d",&n);
getchar();
char s[101];
for(int i=0; i<n; i++) {
fgets(s, sizeof(s), stdin);
// 去除 fgets 可能读取的换行符
s[strcspn(s, "\n")] = 0;
//
if(judge(s)){
printf("YES\n");
} else{
printf("NO\n");
}
}
return 0;
}