PAT (Basic Level) Practise (中文)

1001. 害死人不偿命的(3n+1)猜想 (15)


卡拉兹(Callatz)猜想:

对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……

我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?

输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。

输出格式:输出从n计算到1需要的步数。

输入样例:
3
输出样例:
5



分析:略,看代码就好

代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int n = 0;
	int tmp = 0;
	int count = 0;
	
	scanf("%d", &n);
	if(n>1000){
		
		exit(1);
	}

	tmp = n;
	while(tmp != 1){
		if(tmp%2 == 0)	{
			tmp = tmp/2;
		}else{
			tmp = (tmp*3+1)/2;
		}
		count++;
	}
	printf("%d\n", count);

	return 0;
}

以上为第1001题!

=========================================================

=========================================================

1002. 写出这个数 (20)

读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。

输入格式:每个测试输入包含1个测试用例,即给出自然数n的值。这里保证n小于10100

输出格式:在一行内输出n的各位数字之和的每一位,拼音数字间有1 空格,但一行中最后一个拼音数字后没有空格。

输入样例:
1234567890987654321123456789
输出样例:
yi san wu
分析:输入的数字很长,不可能用int或long来存,要当做字符串读入并存储。输入数据(当做字符串)后,将每个输入的字符转换为数字,并求和;然后将结果转换为字符串,反序存入数组,最后反序病从代码最开始的字符串数组中找到对应的字符串进行输出。

代码:

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 101

int main()
{
	char numberSeq[MAX_SIZE];
	char array[10][5] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
	char result[10];  //max sum of 100 digit is less than 900
	int i = 0;
	int j = 0;
	int sum = 0;
	int size = 0;
	int tmp = 0;
	
	//read in data as string,
	size = read(fileno(stdin), numberSeq, MAX_SIZE) - 1;	
	for(i = 0; i < size; i++)
	{
		sum += (numberSeq[i] - '0');
	}
	
	//transform sum(int) to a reversed string
	//456-->"654"
	tmp = sum;
	while(tmp/10 != 0){
		result[j] = tmp % 10 + '0';
		j++;
		tmp /= 10;
	}
	result[j] = tmp%10 + '0';
	
	//print the string reversely
	//"654"-->4(si)-->5"wu"->6"liu"
	printf("%s", array[result[j]-'0']);
	for(i = j-1; i >= 0; i--)
	{
		printf(" %s", array[result[i]-'0']);
	}

	return 0;
}

以上为第1002题!

=========================================================

=========================================================

1003. 我要通过!(20)

答案正确是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出答案正确,否则输出答案错误

得到答案正确的条件是:

1. 字符串中必须仅有P, A, T这三种字符,不可以包含其它字符;
2. 任意形如 xPATx 的字符串都可以获得答案正确,其中 x 或者是空字符串,或者是仅由字母 A 组成的字符串;
3. 如果 aPbTc 是正确的,那么 aPbATca 也是正确的,其中 a, b, c 均或者是空字符串,或者是仅由字母 A 组成的字符串。

现在就请你为PAT写一个自动裁判程序,判定哪些字符串是可以获得 答案正确 的。

输入格式: 每个测试输入包含1个测试用例。第1行给出一个自然数n (<10),是需要检测的字符串个数。接下来每个字符串占一行,字符串长度不超过100,且不包含空格。

输出格式:每个字符串的检测结果占一行,如果该字符串可以获得答案正确,则输出YES,否则输出NO。

输入样例:
8
PAT
PAAT
AAPATAA
AAPAATAAAA
xPATx
PT
Whatever
APAAATAA
输出样例:
YES
YES
YES
YES
NO
NO
NO
NO
分析:一开始这题看不懂,后来网上找了资料来学习分析才明白点,是正则表达式相关的题目。

经过分析,得出以下结论:

1.输入中必须都是P,A,T字母

2.aPbTc中间插入A,则在最后也要插入与左边a相同个数的A;b不能为空,因为测试用例中的“PT”是错误的

结论:中间b有n个A,则右边的A的个数right是左边A的个数left的n倍,此为核心;剩下的就是如何找到第一个P以及第一个T

代码有两份,一份是参考人家的C++代码,结果完全OK!另一份是自己写的C代码,在本机上用VS2008以及codeblocks运行都没有问题,但是提交到PAT网站后就是通不过,蛋疼啊,以后再研究!

参考网站:

1.http://blog.sina.com.cn/s/blog_932947240101d321.html

2.http://blog.csdn.net/huowei55090521/article/details/8675193

代码1(C++版本--OK):

#include <string>
#include <iostream>

using namespace std;

int main()
{
	int n;
	cin >> n;

	while (n--)
	{
		string s;
		cin >> s;

		size_t p = s.find_first_not_of("A");
		if ((p == string::npos) || (s[p] != 'P'))
		{
			cout << "NO" << endl;
			continue;
		}

		size_t t = s.find_first_not_of("A", p + 1);
		if ((t == string::npos) || (t == p + 1) || (s[t] != 'T'))
		{
			cout << "NO" << endl;
			continue;
		}

		size_t n = s.find_first_not_of("A", t + 1);
		if (n != string::npos)
		{
			cout << "NO" << endl;
			continue;
		}

		if ((s.length() - t - 1) == p * (t - p - 1))
		{
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO" << endl;
		}
	}

	return 0;
}

代码2(C版本--OK on local machine,NOT OK on PAT):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 101

int checkRuleOne(char *str, int n);
int checkAllRule(char *str, int n);


int checkRuleOne(char *str, int n)
{
	int i = 0;
	int flag = 0;

	for(i = 0; i < n; i++){
		if((str[i] == 'P') || (str[i] == 'A') || (str[i] == 'T')){
			flag = 0;
			continue;
		}else{
			flag = 1;
			break;
		}
	}

	if(flag == 1){
		return 1;
	}else{
		return 0;
	}
}


int checkAllRule(char *str, int n)
{
	int i = 0;
	int j = 0;
	int posP = 0;
	int posT = 0;
	int pFound = 0;  //P found if 1
	int tFound = 0;  //T found if 1

	for(i = 0; i < n; i++){
		if(str[i] == 'P'){
			posP = i;
			pFound++;
		}
		if(str[i] == 'T'){
			posT = i;
			tFound++;
		}
	}

	if((pFound == 1) && (tFound == 1)){
		if(posT - posP <= 1){
			return 1;
		}else{
			if(posP*(posT-posP-1) == (n-posT-1)){
				return 0;
			}else{
				return 1;
			}
		}
	}else{
		return 1;
	}
}


int main()
{
	char buf[MAX_SIZE];
	int i = 0;
	int j = 0;
	int nStrings = 0;
	int size = 0;
	
	scanf("%d", &nStrings);
	fflush(stdin);
	for(i = 0; i < nStrings; i++){
		fgets(buf, MAX_SIZE, stdin);
		fflush(stdin);
		
		if(!checkRuleOne(buf, strlen(buf)-1)){
			if(checkAllRule(buf, strlen(buf)-1)){
				printf("NO\n");
			}else{
				printf("YES\n");
			}
		}	
		else{
			printf("NO\n");
		}
	}

	
	return 0;
}


以上为第1003题!

=========================================================


1004. 成绩排名 (20)


读入n名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。

输入格式:每个测试输入包含1个测试用例,格式为

  第1行:正整数n
  第2行:第1个学生的姓名 学号 成绩
  第3行:第2个学生的姓名 学号 成绩
  ... ... ...
  第n+1行:第n个学生的姓名 学号 成绩
其中姓名和学号均为不超过10个字符的字符串,成绩为0到100之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。

输出格式:对每个测试用例输出2行,第1行是成绩最高学生的姓名和学号,第2行是成绩最低学生的姓名和学号,字符串间有1空格。

输入样例:
3
Joe Math990112 89
Mike CS991301 100
Mary EE990830 95
输出样例:
Mike CS991301
Joe Math990112

分析:用结构体存储信息,因为只需要输出最大以及最小,故可以给两个结构体变量,存储最大以及最小,做到on-line,即输入多少都可以知道其最大最小,而且省空间资源。


代码:


#include <stdio.h>
#include <stdlib.h>

typedef struct _StudentInfo{
	char name[11];
	char id[11];
	int grade;
}StudentInfo;


int main()
{
	int N = 0;
	int i;
	StudentInfo max;
	StudentInfo min;
	StudentInfo tmp;
	char tmpName[11];
	char tmpId[11];
	int tmpGrade = 0;
	
	max.grade = 0;
	min.grade = 100;


	scanf("%d", &N);
	for(i = 0; i < N; i++){
		scanf("%s %s %d", tmpName, tmpId, &tmpGrade);
		if(tmpGrade <= min.grade){
			min.grade = tmpGrade;
			strncpy(min.id, tmpId, sizeof(tmpId));
			strncpy(min.name, tmpName, sizeof(tmpName));
		}
		if(tmpGrade >= max.grade){
			max.grade = tmpGrade;
			strncpy(max.id, tmpId, sizeof(tmpId));
			strncpy(max.name, tmpName, sizeof(tmpName));
		}
	}

	printf("%s %s\n", max.name, max.id);
	printf("%s %s\n", min.name, min.id);
	return 0;
}


以上为第1004题!


=========================================================


1005. 继续(3n+1)猜想 (25)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对n=3进行验证的时候,我们需要计算3、5、8、4、2、1,则当我们对n=5、8、4、2进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这4个数已经在验证3的时候遇到过了,我们称5、8、4、2是被3“覆盖”的数。我们称一个数列中的某个数n为“关键数”,如果n不能被数列中的其他数字所覆盖。

现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式:每个测试输入包含1个测试用例,第1行给出一个正整数K(<100),第2行给出K个互不相同的待验证的正整数n(1<n<=100)的值,数字间用空格隔开。

输出格式:每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用1个空格隔开,但一行中最后一个数字后没有空格。

输入样例:
6
3 5 6 7 8 11
输出样例:
7 6

分析:刚开始没思路,后来看了参考代码才明白。建一个数组num[101],大小为101(最大下标为100,因为K个正整数最大100),初始化全-1,然后输入初始数组,并将num[tmp]置0,接下来对每个输入的数据进行分析,依据(3n+1)猜想的思路,判断过程中出现的数据并在数组中做标记,置1.  最后打印时,只打印数组元素为0的,因为为1表示可以被“覆盖”,为“-1”都没有访问过,为“0”才表示没有覆盖,而且是数组中的元素,逆序打印,刚好可以从大到小进行打印。

代码:

#include<stdio.h>
#include<string.h>
#include<memory.h>


int main()
{
	int n;
	int tmp;
	int num[101];
	int i;
	int isfirst;

	memset(num, -1, sizeof(num));
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d",&tmp);
		num[tmp] = 0;  //wait to check
	}

	for(i = 0 ; i < 101 ; i++)
	{
		if(num[i] == 0)
		{
			tmp = i;
			while(tmp!=1)            
			{
				if( tmp % 2 == 0)                         
				{    
					tmp = tmp / 2;
				}                                    
				else                                 
				{    
					tmp = (3*tmp+1) / 2;
				}
				if(tmp < 101 && num[tmp] != -1)
					num[tmp] = 1;  //occupy  
			}
		}
	}

	isfirst = 1;
	for(i = 100; i >= 0 ; i--)
	{

		if(num[i] == 0)  //not be occupied
		{
			if(!isfirst)
				printf(" ");
			printf("%d",i);
			isfirst = 0;
		}
	}    
	
	printf("\n");
	return 0;
}


参考:http://linest.github.io/blog/2013/04/13/1/

以上为第1005题!

=========================================================

1006. 换个格式输出整数 (15)

让我们用字母B来表示“百”、字母S表示“十”,用“12...n”来表示个位数字n(<10),换个格式来输出任一个不超过3位的正整数。例如234应该被输出为BBSSS1234,因为它有2个“百”、3个“十”、以及个位的4。

输入格式:每个测试输入包含1个测试用例,给出正整数n(<1000)。

输出格式:每个测试用例的输出占一行,用规定的格式输出n。

输入样例1:
234
输出样例1:
BBSSS1234
输入样例2:
23
输出样例2:
SS123
分析:简单的很,可以入参考资料中的那样很简单的输出就好 代码:
#include<stdio.h>
#include<string.h>
#include<memory.h>


int main()
{
	int N;
	int a[3];
	int i = 0;
	int j = 0;
	int k = 0;
	int tmp;

	memset(a, 0, 3*4);

	scanf("%d", &N);
	while(N / 10 != 0){
		a[i++] = N % 10;
		N /= 10;
	}
	a[i] = N;

	for(j = i; j >= 0; j--){
		tmp = a[j];
		if(tmp != 0){
			switch(j){
				case 2:
					for(k = 0; k < tmp; k++){
						printf("%c", 'B');
					}
					break;
				case 1:
					for(k = 0; k < tmp; k++){
						printf("%c", 'S');
					}
					break;
				case 0:
					for(k = 0; k < tmp; k++){
						printf("%c", '0' + k + 1);
					}
					break;
				default:
					break;
			}
		}	
	}

	return 0;
}

参考:http://linest.github.io/blog/2013/04/13/1/

=========================================================

1007. 素数对猜想 (20)

让我们定义 dn 为:dn = pn+1 - pn,其中 pi 是第i个素数。显然有 d1=1 且对于n>1有 dn 是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。

现给定任意正整数N (< 105),请计算不超过N的满足猜想的素数对的个数。

输入格式:每个测试输入包含1个测试用例,给出正整数N。

输出格式:每个测试用例的输出占一行,不超过N的满足猜想的素数对的个数。

输入样例:
20
输出样例:
4
分析:本质上就是求素数的问题,IsPrime函数中对n=2以及n=1进行判断,当输入为1或者2时,循环直接跳出,count仍旧为0,符合题意

代码:

#include<stdio.h>
#include<math.h>


//return 1 if n is a prime, return 0 if not
int IsPrime(int n)
{
	int res = 1;
	int i = 0;

	if(n == 1 || ((n > 2) && (n % 2 == 0))) //even or 1       
	{
		res = 0;
		return res;
	}
	
	if(n == 2){
		res = 1;
		return res;
	}

	for(i = 3; i <= sqrt(n) ; i+=2)
	{
		if( n % i == 0)  //not a prime
		{
			res = 0;
			break;
		}
	}//end of loop , is a prime
	return res;
}

int main()
{
	int n;
	int prevprime = 3;  //start from 3
	int count = 0;
	int i = 0;


	scanf("%d",&n);
	//if n == 1 or 2, count = 0
	for(i = 3 ; i <= n ; i += 2 )
	{
		if(IsPrime(i))
		{
			if(i - prevprime == 2){
				count++;
			}	
			prevprime = i;
		}
	}

	printf("%d\n",count);
	return 0;
}

以上为第1007题!

=========================================================

1008. 数组元素循环右移问题 (20)

一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0A1……AN-1)变换为(AN-M …… AN-1 A0 A1……AN-M-1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?

输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100)、M(M>=0);第2行输入N个整数,之间用空格分隔。

输出格式:在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。

输入样例:
6 2
1 2 3 4 5 6
输出样例:
5 6 1 2 3 4
分析:注意m可能大于n, 故需要取模运算

方法一:比较笨的方法就是将整个数组一次向右移动一位,移动M次,移动次数总共有M*N次

方法二:比较巧。数组A0...An-m-1An-m...An-1,先将整个数组翻转一边An-1...An-mAn-m-1...A0,然后取前m个翻转,再取后n-m个翻转,就形成An-m...An-1A0...An-m-1,总共移动次数需要3次倒序就可以。

代码:

#include<stdio.h>
#include<math.h>

int Reverse(int a[], int N)
{
	int i;
	int tmp;

	for(i = 0; i < N/2; i++){
		tmp = a[i];
		a[i] = a[N - 1 - i];
		a[N - 1 -i] = tmp;	
	}
}

int main()
{
	int n = 0;
	int m = 0;
	int i = 0;
	int *a = NULL;
	int isfirst = 1;

	scanf("%d %d", &n, &m);
	a = malloc(n*sizeof(int));
	for(i = 0; i < n; i++){
		scanf("%d", &a[i]);
	}
	
	Reverse(a, n);
	Reverse(a, m%n);
	Reverse(a+m%n, n-m%n);
	for(i = 0; i < n; i++){
		if(isfirst){
			printf("%d", a[i]);
			isfirst = 0;
		}else{
			printf(" %d", a[i]);
		}
	}
	printf("\n");
	return 0;
}

以上为第1008题!

=========================================================

1009. 说反话 (20)

给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。

输入格式:测试输入包含一个测试用例,在一行内给出总长度不超过80的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用1个空格分开,输入保证句子末尾没有多余的空格。

输出格式:每个测试用例的输出占一行,输出倒序后的句子。

输入样例:
Hello World Here I Come
输出样例:
Come I Here World Hello
分析:刚开始享用fgets来将输入的整个字符串一次性读入,然后再用strtok来分别隔开每个单词(以空格“ ”),但是如果字符串自由一个单词(从头到尾没有空格来分割),貌似strtok不太好处理,然后就用了下面这个方法

代码:

#include<stdio.h>
#include<string.h>

int main()
{
	char inputs[81][81];
	char str[81];
	char ch;
	int count = 0;
	int i;

	while(scanf("%s%c",str,&ch))
	{
		strncpy(inputs[count],str, strlen(str));
		inputs[count++][strlen(str)] = '\0';
		if(ch=='\n')
			break;
	}

	for(i = count-1; i >= 0; i--)
	{
		printf("%s", inputs[i]);
		if(i != 0)
			printf(" ");

	}

	printf("\n");
	return 0;
}

以上为第1009题!

=========================================================

1010. 一元多项式求导 (25)

设计函数求一元多项式的导数。

输入格式:以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式:以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。

输入样例:
3 4 -5 2 6 1 -2 0
输出样例:
12 3 -10 1 6 0
分析:这题题意不是很清晰,本来理解上输出非零项的系数和指数么,结果当输入“n 0”时必须输出“0 0”才能满足要求,并且需要注意指数为负数的情况。本人的程序中全部用数组来进行存储,也可以参照例子中的程序,变输入数据边输出,on-line。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MaxNumber 1000

int main()
{
	int arr[MaxNumber];
	int i = 0;
	int j = 0;
	int k = 0;
	int isfirst;
	char ch;
	int data;
	int coeff;
	int expo;

	while(scanf("%d%c", &data, &ch)){
		arr[i++] = data;
		if(ch == '\n'){
			break;
		}
	}

	for(j = 0; j < i;){
		coeff = arr[j++];
		expo = arr[j++];
		if(expo != 0){
			arr[j - 2] = coeff * expo;
			arr[j - 1] = expo - 1;
		}else{
			arr[j - 2] = 0;
			arr[j - 1] = 0;
		}
	}

	isfirst = 1;
	for(k = 0; k < j; k += 2){
		if(arr[k] == 0){
			continue;
		}else{
			if(isfirst == 1){
				printf("%d %d", arr[k], arr[k + 1]);
				isfirst = 0;
			}else{
				printf(" %d %d", arr[k], arr[k + 1]);
			}
		}	
	}

	if(isfirst){
		printf("0 0");
	}

	printf("\n");


	return 0;
}
参考代码:

#include<stdio.h>

int main()
{
  int cof;
  int exp;
  int isfirst = 1;
  while(scanf("%d%d",&cof,&exp)!=EOF)
  {
      if(exp != 0)
      {
          if(!isfirst)
              printf(" ");          
          printf("%d %d",cof*exp,exp-1);
          isfirst = 0;
      }
      
  }
  if(isfirst)
      printf("0 0");
  return 0;
}
参考来源: http://linest.github.io/blog/2013/04/13/1/

以上为第1010题!

=========================================================

打完收工啦!




你可能感兴趣的:(pat)