c语言pta练习集

本篇博客记录了我在刷题过程中遇到的一些没有思路或者借鉴了别人比较好的实现方法

L1-002 打印沙漏*

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
 ***
  *
 ***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
 ***
  *
 ***
*****
2

实现思路

         本题个人觉得有一点绕,建议先理清楚思路再进行作答,首先判断出需要输出多少行(总数加起来大于所给的星星,进行回退一次),然后找规律,每行需要输出多少个空格,需要输出多少个字符,最后进行输出

代码实现

#include
 
int main() {
    int n; // 输入的符号数量
    char c; // 要打印的符号
    scanf("%d %c", &n, &c); // 读取输入
    int sum = 0; // 用于存储每一行的符号数量总和
    int i = 1; // 用于循环的变量,初始为1,每次递增2
    // 计算沙漏的高度(从顶部到中心)并找到对应的行数
    for (i = 3;; i += 2) {
        sum += i; // 增加当前行的符号数量
        if (sum * 2 + 1 > n) { // 如果总符号数量超过输入数量,则退出循环
            i = i - 2; // 回退一行
            break;
        }
    }
    int temp = i; // 临时变量,用于保存沙漏的高度
 
    int count = 0; // 用于计算每行需要打印的符号数量
    // 打印沙漏的上半部分
    while (i > 0) {
        count = 0; // 初始化每行的符号数量
        for (int j = i; j > 0; j--) {
            count++; // 增加当前行的符号数量
        }
        // 打印每行前面的空格
        for (int q = 0; q < (temp - count) / 2; q++) printf(" ");
        // 打印当前行的符号
        for (int j = i; j > 0; j--) {
            printf("%c", c);
            count++;
        }
        printf("\n"); // 换行
        i = i - 2; // 递减,准备打印下一行
    }
 
    i = i + 4; // 恢复 i 的值,用于打印沙漏的下半部分
    // 打印沙漏的下半部分
    while (i <= temp) {
        count = 0; // 初始化每行的符号数量
        for (int j = i; j > 0; j--) {
            count++; // 增加当前行的符号数量
        }
        // 打印每行前面的空格
        for (int q = 0; q < (temp - count) / 2; q++) printf(" ");
        // 打印当前行的符号
        for (int j = i; j > 0; j--) {
            printf("%c", c);
            count++;
        }
        printf("\n"); // 换行
        i = i + 2; // 递增,准备打印下一行
    }
    // 计算并打印剩余的符号数量
    sum = 0;
    while (temp > 1) {
        sum += temp; // 增加当前行的符号数量总和
        temp -= 2; // 减少行数
    }
    sum = sum * 2 + 1; // 计算剩余符号数量
    printf("%d", n - sum); // 打印剩余符号数量
    return 0;
}

 L1-006 连续因子**

一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3×5×6×7,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

输入格式:

输入在一行中给出一个正整数 N(1

输出格式:

首先在第 1 行输出最长连续因子的个数;然后在第 2 行中按 因子1*因子2*……*因子k 的格式输出最小的连续因子序列,其中因子按递增顺序输出,1 不算在内。

输入样例:

630

输出样例:

3
5*6*7

实现思路

1.采用枚举的办法,从2开始循环,找该数的连续因子,并且记录连续因子的长度和开始的值

2.输出最长连续因子的个数以及最小的连续因子序列。

代码实现

#include
#include

int main() {
    int n;
    scanf("%d",&n);
    int max=0,start=0;//最长连续字串长度和开始下标 
    for(int i=2;imax){
            start=i;
            max=count;
        }
    }
    if(max==0){
        printf("1\n");
        printf("%d",n);
    }else{
        printf("%d\n",max);
        for(int i=start;i

 L1-009 N个数求和*

本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。

输入格式:

输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b1 a2/b2 ...给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。

输出格式:

输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。

实现思路

先找分母的最小公倍数,通分,然后找分子和分母的最大公约数,约分,根据条件进行输出。

(为什么要找最小公倍数,如果直接每个分母相乘,可能会造成溢出)

代码实现

#include

//最大公约数 
long gcd(long a,long b){
    while(b!=0){
        long temp=b;
        b=a%b;
        a=temp;
    }
    return a;
} 
//最小公倍数 
long lcm(long a,long b){
    return a*b/gcd(a,b);
}


int main() {
    int n;
    scanf("%d",&n);
    long son[n],dad[n],sum1=0,sum2=1;
    for(int i=0;i 0) {
            printf("%ld ", sum1 / sum2);
            sum1 = sum1 - sum2 * (sum1 / sum2);
        }
        printf("%ld/%ld\n", sum1, sum2);
    }
    return 0;
}

L1-011 A-B*

本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。

输入格式:

输入在2行中先后给出字符串A和B。两字符串的长度都不超过104,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束。

输出格式:

在一行中打印出A−B的结果字符串。

输入样例:

I love GPLT!  It's a fun game!
aeiou

输出样例:

I lv GPLT!  It's  fn gm!

实现思路

用一个辅助数组count,记录下b数组中出现过的字符,遍历a字符,如果在b中没有出现过就输出

代码实现

#include
#include

int main() {
    char a[10001],b[10001];
    int q=0,p=0;
    while((a[q]=getchar())!='\n'){
        q++;
    }
    while((b[p]=getchar())!='\n'){
        p++;
    }
    int count[129]={0};
    for(int i=0;i

 L1-020 帅到没朋友*

当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为太帅而没有朋友。本题就要求你找出那些帅到没有朋友的人。

输入格式:

输入第一行给出一个正整数N(≤100),是已知朋友圈的个数;随后N行,每行首先给出一个正整数K(≤1000),为朋友圈中的人数,然后列出一个朋友圈内的所有人——为方便起见,每人对应一个ID号,为5位数字(从00000到99999),ID间以空格分隔;之后给出一个正整数M(≤10000),为待查询的人数;随后一行中列出M个待查询的ID,以空格分隔。

注意:没有朋友的人可以是根本没安装“朋友圈”,也可以是只有自己一个人在朋友圈的人。虽然有个别自恋狂会自己把自己反复加进朋友圈,但题目保证所有K超过1的朋友圈里都至少有2个不同的人。

输出格式:

按输入的顺序输出那些帅到没朋友的人。ID间用1个空格分隔,行的首尾不得有多余空格。如果没有人太帅,则输出No one is handsome

注意:同一个人可以被查询多次,但只输出一次。

实现思路

这道题目看起来比较复杂,其实和上题类型用一个大数组标识出现过的id号,然后遍历输出没有朋友的人

代码实现

#include 

int main()
{
	int order[100000] = { 0 };//定义一个大数组用于标识出现过的id号 
	int n, k, m, check;   
	int i, j, d = 0, s, sum = 0;   //d为判断空格的标志; sum为“没朋友”的总人数
	scanf("%d", &n);
	for (i = 0; i < n; i++)      //将朋友圈所有的人接收进来,按要求对order数组进行更改
	{
		scanf("%d", &k);
		if (k == 1)
		{
			scanf("%d", &s);
			continue;
		}
		for (j = 0; j < k; j++)
		{
			scanf("%d", &s);
			order[s]++;
		}
	}
	scanf("%d", &m);
	for (i = 0; i < m; i++)
	{
		scanf("%d", &check);
		if (order[check] == 0)   //判断是否“没朋友”,若是则按格式输出
		{
			if (d == 0)
				d++;
			else
				printf(" ");
			printf("%05d", check);
			order[check] = 1;  //将已经输出“没朋友”的人看作“有朋友”,防止重复导致的第二次输出
			sum++;
		}
	}
	if (sum == 0)
		printf("No one is handsome");
	return 0;
}

L1-025 正整数A+B*

题的目标很简单,就是求两个正整数AB的和,其中AB都在区间[1,1000]。稍微有点麻烦的是,输入并不保证是两个正整数。

输入格式:

输入在一行给出AB,其间以空格分开。问题是AB不一定是满足要求的正整数,有时候可能是超出范围的数字、负数、带小数点的实数、甚至是一堆乱码。

注意:我们把输入中出现的第1个空格认为是AB的分隔。题目保证至少存在一个空格,并且B不是一个空字符串。

输出格式:

如果输入的确是两个正整数,则按格式A + B = 和输出。如果某个输入不合要求,则在相应位置输出?,显然此时和也是?

输入样例1:

123 456

输出样例1:

123 + 456 = 579

输入样例2:

22. 18

输出样例2:

? + 18 = ?

输入样例3:

-100 blabla bla...33

输出样例3:

? + ? = ?

实现思路

遍历a和b,如果有字符不符合数字的情况,就标记,如果都是数字,转成int类型用于计算,最后根据题意进行输出

代码实现

#include 

int main() {
    char a[1001], b[1001];
    int p = 0;
    while ((a[p] = getchar()) != ' ') {
        p++;
    }
    int q = 0;
    while ((b[q] = getchar()) != '\n') {
        q++;
    }
    int flaga = 0, flagb = 0, suma = 0, sumb = 0, flag = 1;
    for (int i = p - 1; i >= 0; i--) {
        if (a[i] < '0' || a[i] > '9') {
            flaga = 1;
            break;
        } else {
            suma = suma + (a[i] - '0') * flag;
            flag *= 10;
        }
    }
    flag = 1;
    for (int i = q-1; i >= 0; i--) {
        if (b[i] < '0' || b[i] > '9') {
            flagb = 1;
            break;
        } else {
            sumb += (b[i] - '0') * flag;
            flag *= 10;
        }
    }
    if(suma>1000||suma<1) flaga++;
    if(sumb>1000||sumb<1) flagb++;
    if (flaga == 0 && flagb == 0) {
        printf("%d + %d = %d\n", suma, sumb, suma + sumb);
    } else if (flaga == 0 && flagb != 0) {
        printf("%d + ? = ?\n", suma);
    } else if (flaga != 0 && flagb == 0) {
        printf("? + %d = ?\n", sumb);
    } else {
        printf("? + ? = ?\n");
    }
    return 0;
}

 L1-033 出生年*

以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话。

以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话。

输入格式:

输入在一行中给出出生年份y和目标年份中不同数字的个数n,其中y在[1, 3000]之间,n可以是2、或3、或4。注意不足4位的年份要在前面补零,例如公元1年被认为是0001年,有2个不同的数字0和1。

输出格式:

根据输入,输出x和能达到要求的年份。数字间以1个空格分隔,行首尾不得有多余空格。年份要按4位输出。注意:所谓“n个数字都不相同”是指不同的数字正好是n个。如“2013”被视为满足“4位数字都不同”的条件,但不被视为满足2位或3位数字不同的条件。

输入样例1:

1988 4

输出样例1:

25 2013

输入样例2:

1 2

输出样例2:

0 0001

实现思路

枚举,用一个数组用于存储出现过的数字(这种思想其实很常用),如果出现过的数字等于所给的n(证明有n个不同的数),结束循环,输出

代码实现

/*我出生于y年,直到x岁才遇到n个数字都不相同的年份*/ 

#include
int main()
{
    int i,y,x,n,temp,count=0;
    scanf("%d %d",&y,&n);
    int arr[10]={0};
    for(i=y;;i++){
        temp=i;
        for(int q=0;q<4;q++){
            arr[i%10]++;
            i=i/10;
        }
        for(int j=0;j<10;j++){
            if(arr[j]!=0) count++;
        }
        if(count==n){
            printf("%d %04d",temp-y,temp);
            break;
        }
        count=0;
        i=temp;
        for(int p=0;p<10;p++){
            arr[p]=0;
        }
    } 
	return 0;
}

 L1-035 情人节*

以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家。第2个赞和第14个赞的,我介绍你俩认识…………咱三吃饭…你俩请…”。现给出此贴下点赞的朋友名单,请你找出那两位要请客的倒霉蛋。

以上是朋友圈中一奇葩贴:“2月14情人节了,我决定造福大家。第2个赞和第14个赞的,我介绍你俩认识…………咱三吃饭…你俩请…”。现给出此贴下点赞的朋友名单,请你找出那两位要请客的倒霉蛋。

输入格式:

输入按照点赞的先后顺序给出不知道多少个点赞的人名,每个人名占一行,为不超过10个英文字母的非空单词,以回车结束。一个英文句点.标志输入的结束,这个符号不算在点赞名单里。

输出格式:

根据点赞情况在一行中输出结论:若存在第2个人A和第14个人B,则输出“A and B are inviting you to dinner...”;若只有A没有B,则输出“A is the only one for you...”;若连A都没有,则输出“Momo... No one is for you ...”。

实现思路

输入每个人的人名,并且统计输入的人名的个数,然后将第二个和第14个人的人名复制出来,根据条件进行输出

代码实现

#include 
#include 

int main() {
    int count=0;
    char a[11],b[11];
    while(1){
        char name[11];
        scanf("%s",name);
        count++;
        if(count==2){
            strcpy(a,name);
        }
        if(count==14){
            strcpy(b,name);
        }
        if(strlen(name)==1&&name[0]=='.') break;
    }
    count--;
    if(count<2){
        printf("Momo... No one is for you ...");
    }else if(count<14){
        printf("%s is the only one for you...",a);
    }else{
        printf("%s and %s are inviting you to dinner...",a,b);
    }
    return 0;
}

L1-039 古风排版*

中国的古人写文字,是从右向左竖向排版的。本题就请你编写程序,把一段文字按古风排版。

输入格式:

输入在第一行给出一个正整数N(<100),是每一列的字符数。第二行给出一个长度不超过1000的非空字符串,以回车结束。

输出格式:

按古风格式排版给定的字符串,每列N个字符(除了最后一列可能不足N个)。

输入样例:

4
This is a test case

输出样例:

asa T
st ih
e tsi
 ce s

实现思路

计算所需二维数组的行数和列数,从又开始复制字符串,并计数,需要注意的就是如果大于字符串的长度后续的字符置为“ ”

代码实现

#include 

int main() {
    int n;
    scanf("%d",&n);getchar();
    char s[1001];int index=0;
    while((s[index]=getchar())!='\n'){
        index++;
    }   
    int row=(index-1)/n+1; //列数 
    int line=n;
    char num[line][row];
    int k=0;
    for(int j=row-1;j>=0;j--){
        for(int i=0;i

 L1-043 阅览室*

天梯图书阅览室请你编写一个简单的图书借阅统计程序。当读者借书时,管理员输入书号并按下S键,程序开始计时;当读者还书时,管理员输入书号并按下E键,程序结束计时。书号为不超过1000的正整数。当管理员将0作为书号输入时,表示一天工作结束,你的程序应输出当天的读者借书次数和平均阅读时间。

注意:由于线路偶尔会有故障,可能出现不完整的纪录,即只有S没有E,或者只有E没有S的纪录,系统应能自动忽略这种无效纪录。另外,题目保证书号是书的唯一标识,同一本书在任何时间区间内只可能被一位读者借阅。

输入格式:

输入在第一行给出一个正整数N(≤10),随后给出N天的纪录。每天的纪录由若干次借阅操作组成,每次操作占一行,格式为:

书号([1, 1000]内的整数) 键值SE) 发生时间hh:mm,其中hh是[0,23]内的整数,mm是[0, 59]内整数)

每一天的纪录保证按时间递增的顺序给出。

输出格式:

对每天的纪录,在一行中输出当天的读者借书次数和平均阅读时间(以分钟为单位的精确到个位的整数时间)。

实现思路

定义一个结构体,用于记录每本书的借出时间,归还时间和状态,根据条件进行输出,每天重新进行初始化,根据条件计算时间并输出。

代码实现

#include
typedef struct book{
    char status;
    int hour;
    int min;
    int flag;
}book;

int main(){
    int n;
    scanf("%d",&n);    
    for(int i=0;i

 L1-046 整除光棍**

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:

输入在一行中给出一个不以5结尾的正奇数x(<1000)。

输出格式:

在一行中输出相应的最小的sn,其间以1个空格分隔。

思路实现:

依次遍历找到这个光棍数,光棍数对x取余等于0,但难点在于,光棍数可能是个非常大的数,会造成溢出,考虑模拟我们人工计算除法的过程,手工除,如果不够除进位+1(类比大数的阶乘,模拟乘法过程的实现)

代码实现

#include
int main()
{
    int x = 0;
    scanf("%d",&x);
    int n = 1;
    int count = 1;
    //找出首个比x大的光棍数 
    while(n

L1-048 矩阵A乘以B*

给定两个矩阵A和B,要求你计算它们的乘积矩阵AB。需要注意的是,只有规模匹配的矩阵才可以相乘。即若A有Ra​行、Ca​列,B有Rb​行、Cb​列,则只有Ca​与Rb​相等时,两个矩阵才能相乘。

输入格式:

输入先后给出两个矩阵A和B。对于每个矩阵,首先在一行中给出其行数R和列数C,随后R行,每行给出C个整数,以1个空格分隔,且行首尾没有多余的空格。输入保证两个矩阵的R和C都是正数,并且所有整数的绝对值不超过100。

输出格式:

若输入的两个矩阵的规模是匹配的,则按照输入的格式输出乘积矩阵AB,否则输出Error: Ca != Rb,其中Ca是A的列数,Rb是B的行数。

输入样例1:

2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

输出样例1:

2 4
20 22 24 16
53 58 63 28

实现思路

三个for循环,行列相乘再相加,关键是找到下标

代码实现

#include 
int main()
{
    int a,b;
    scanf("%d %d",&a,&b);
    int num1[a][b];
    for(int i=0;i

L1-049 天梯赛座位分配**

 天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员…… 以此类推。如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。

输入格式:

输入在一行中给出参赛的高校数 N (不超过100的正整数);第二行给出 N 个不超过10的正整数,其中第 i 个数对应第 i 所高校的参赛队伍数,数字间以空格分隔。

输出格式:

从第 1 所高校的第 1 支队伍开始,顺次输出队员的座位号。每队占一行,座位号间以 1 个空格分隔,行首尾不得有多余空格。另外,每所高校的第一行按“#X”输出该校的编号X,从 1 开始。

思路实现

这道题我觉得实现起来很复杂,还在思考有没有好一点的实现思路(欢迎大家指导)

代码实现

#include 
#include 
int main()
{
    int n = 0;
    scanf("%d",&n);
    const int N = 106;
    int arr[N];
    for(int i = 1;i<=n;i++)
        scanf("%d",&arr[i]);
    for(int i = 1;i<=n;i++)//第几个学校
    {
        
        printf("#%d\n",i);
        int count = 0;//每个学校排了几个人
        int n1 = 2;//注意一个学校的情况
        if(n>=2)
            n1 = n;//可以理解为一次性排几个座位
        int q = i;//当前学校的队员的座位号
        for(int j = 1;j<=arr[i];j++)//当前学校的队伍数
        {
            int flag = 0;
            for(int k = 1;k<=10;k++)//一个队伍10人
            {
                if(flag)
                    printf(" ");
                flag = 1;
                printf("%d",q);
                count++;//每个学校排了几个人
                if(count%10==0)
                {//可以优化,count%10==0才进入循环,(优化后发的,也可以去掉if)
                    for(int o = 1;o2)
                            n1--;//排的座位数-1
                    }
                }
                q+=n1;//该学校下一个队员的座位号
                if(count%10==0)
                {
                    for(int o = i+1;o<=n;o++)//看后面学校是否有排完的
                    {
                        if(count==(arr[o]*10) && n1>2)
                            n1--;//排的座位数-1
                    }
                }
            }
            printf("\n");
        }
    }
    return 0;
}

 L1-054 福到了*

“福”字倒着贴,寓意“福到”。不论到底算不算民俗,本题且请你编写程序,把各种汉字倒过来输出。这里要处理的每个汉字是由一个 N × N 的网格组成的,网格中的元素或者为字符 @ 或者为空格。而倒过来的汉字所用的字符由裁判指定。

输入格式:

输入在第一行中给出倒过来的汉字所用的字符、以及网格的规模 N (不超过100的正整数),其间以 1 个空格分隔;随后 N 行,每行给出 N 个字符,或者为 @ 或者为空格。

输出格式:

输出倒置的网格,如样例所示。但是,如果这个字正过来倒过去是一样的,就先输出bu yong dao le,然后再用输入指定的字符将其输出。

实现思路

用二维数组进行输入,用输入的字符替代数组里的字符,判断倒过来是否相同(这个地方如果不会看一遍就会了),逆向输出

代码实现

#include 
#include 
int main()
{   
    //输入 
    char c;int n;
    scanf("%c %d",&c,&n);
    getchar();
    char num[n+1][n+1];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%c",&num[i][j]);
        }
        getchar();
    }
    int flag=1;
    //判断正过来和倒过去是否一样
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(num[i][j]!=num[n-i+1][n-j+1]) flag=0;
        }
    }
    //输出 
    if(flag==1) printf("bu yong dao le\n");
    for(int i=n;i>=1;i--){
        for(int j=n;j>=1;j--){
            if(num[i][j]!=' '){
                num[i][j]=c;
            }
            printf("%c",num[i][j]);
        }
        printf("\n");
    }
    return 0;
}

 L1-058 6翻了*

“666”是一种网络用语,大概是表示某人很厉害、我们很佩服的意思。最近又衍生出另一个数字“9”,意思是“6翻了”,实在太厉害的意思。如果你以为这就是厉害的最高境界,那就错啦 —— 目前的最高境界是数字“27”,因为这是 3 个 “9”!

本题就请你编写程序,将那些过时的、只会用一连串“6666……6”表达仰慕的句子,翻译成最新的高级表达。

输入格式:

输入在一行中给出一句话,即一个非空字符串,由不超过 1000 个英文字母、数字和空格组成,以回车结束。

输出格式:

从左到右扫描输入的句子:如果句子中有超过 3 个连续的 6,则将这串连续的 6 替换成 9;但如果有超过 9 个连续的 6,则将这串连续的 6 替换成 27。其他内容不受影响,原样输出。

实现思路

遍历字符串,有连续的6就进行计数,有超过 3 个连续的 6,则将这串连续的 6 替换成 9;但如果有超过 9 个连续的 6,则将这串连续的 6 替换成 27。没有的话回退,正常输出

代码实现

#include 

int main()
{   
    char s[1001];
    int index=0;
    while((s[index]=getchar())!='\n'){
        index++;
    }
    for(int i=0;i3&&count<=9) {printf("9");i--;}
        else if(count>9) {printf("27");i--;}
        else printf("%c",s[i]);
    }   
    return 0;
}

 L1-086 斯德哥尔摩火车上的题*

上图是新浪微博上的一则趣闻,是瑞典斯德哥尔摩火车上的一道题,看上去是段伪代码:

s = ''
a = '1112031584'
for (i = 1; i < length(a); i++) {
  if (a[i] % 2 == a[i-1] % 2) {
    s += max(a[i], a[i-1])
  }
}
goto_url('www.multisoft.se/' + s)

其中字符串的 + 操作是连接两个字符串的意思。所以这道题其实是让大家访问网站 www.multisoft.se/112358注意:比赛中千万不要访问这个网址!!!)。

当然,能通过上述算法得到 112358 的原始字符串 a 是不唯一的。本题就请你判断,两个给定的原始字符串,能否通过上述算法得到相同的输出?

输入格式:

输入为两行仅由数字组成的非空字符串,长度均不超过 104,以回车结束。

输出格式:

对两个字符串分别采用上述斯德哥尔摩火车上的算法进行处理。如果两个结果是一样的,则在一行中输出那个结果;否则分别输出各自对应的处理结果,每个占一行。题目保证输出结果不为空。

输入样例 1:

1112031584
011102315849

输出样例 1:

112358

输入样例 2:

111203158412334
12341112031584

输出样例 2:

1123583
112358

实现思路

输入两个字符串,实现一个图片所示的函数对两个字符串进行处理,比较两个字符串,根据条件进行输出

代码实现

#include 
#include 
#include 

int max(int a, int b){
    return a > b ? a : b;
}

char* toNum(char a[]){
    char *s = (char*)malloc(10001 * sizeof(char)); // 分配动态内存
    int index = 0;
    for (int i = 1; i < strlen(a); i++) {
        if (a[i] % 2 == a[i - 1] % 2){
            s[index] = max((int)a[i], (int)a[i - 1]);
            index++;
        }
    }
    return s;
}

int main(){
    char s1[10001], s2[10001];
    gets(s1);
    gets(s2); 
    char *a = toNum(s1);
    char *b = toNum(s2);
    if(strcmp(a, b) == 0){
        printf("%s", a);
    }else{
        printf("%s\n%s", a, b);
    }
    free(a); 
    free(b);
    return 0;
}

L1-088 静静的推荐*

天梯赛结束后,某企业的人力资源部希望组委会能推荐一批优秀的学生,这个整理推荐名单的任务就由静静姐负责。企业接受推荐的流程是这样的:

  • 只考虑得分不低于 175 分的学生;
  • 一共接受 K 批次的推荐名单;
  • 同一批推荐名单上的学生的成绩原则上应严格递增;
  • 如果有的学生天梯赛成绩虽然与前一个人相同,但其参加过 PAT 考试,且成绩达到了该企业的面试分数线,则也可以接受。

给定全体参赛学生的成绩和他们的 PAT 考试成绩,请你帮静静姐算一算,她最多能向企业推荐多少学生?

输入格式:

输入第一行给出 3 个正整数:N(≤105)为参赛学生人数,K(≤5×103)为企业接受的推荐批次,S(≤100)为该企业的 PAT 面试分数线。

随后 N 行,每行给出两个分数,依次为一位学生的天梯赛分数(最高分 290)和 PAT 分数(最高分 100)。

输出格式:

在一行中输出静静姐最多能向企业推荐的学生人数。

输入样例:

10 2 90
203 0
169 91
175 88
175 0
175 90
189 0
189 0
189 95
189 89
256 100

输出样例:

8

样例解释:

第一批可以选择 175、189、203、256 这四个分数的学生各一名,此外 175 分 PAT 分数达到 90 分的学生和 189 分 PAT 分数达到 95 分的学生可以额外进入名单。第二批就只剩下 175、189 两个分数的学生各一名可以进入名单了。最终一共 8 人进入推荐名单。

实现思路

本题有一个使用了之前提到到的一个惯用操作,定义一个辅助数组记录出现的次数,这里的k批其实代表的就算出现k次

代码实现

#include 

typedef struct student{
    int score;
    int pat;
}student;

int main() {
    int n,k,s;
    scanf("%d %d %d",&n,&k,&s);
    student std[n];
    for(int i=0;i=175&&num[std[j].score]=175&&std[j].pat>=s){
            count++;
        }
    }
    printf("%d",count);
}

6-10 阶乘计算升级版**

本题要求实现一个打印非负整数阶乘的函数

函数接口定义:

void Print_Factorial ( const int N );

裁判测试程序样例:

#include 

void Print_Factorial ( const int N );

int main()
{
    int N;
    
    scanf("%d", &N);
    Print_Factorial(N);
    return 0;
}

/* 你的代码将被嵌在这里 */

思路实现

本题的难点在于大数的阶乘会造成溢出,我们需要用字符数组来进行存储,手工模拟乘法的过程,然后遍历逆序输出(和之前的整除光棍一样都是溢出的问题,只能采用字符串,手工模拟乘和除的过程)

接口实现

void Print_Factorial(const int N) {
    if (N < 0) {
        printf("Invalid input");
    } else if (N == 0) {
        printf("1");
    } else {
        // 初始化sum数组为全零
        int sum[10001] = {0};
        sum[0] = 1; // 阶乘初始为1

        // 计算阶乘
        for (int i = 2; i <= N; i++) {
            int up = 0; // 进位
            for (int j = 0; j < 10001; j++) {
                int temp = sum[j] * i + up;
                sum[j] = temp % 10;
                up = temp / 10;
            }
        }
        // 找到最后一个非零位
        int lastNonZero = 10000;
        while (sum[lastNonZero] == 0) {
            lastNonZero--;
        }
        // 打印阶乘结果
        for (int i = lastNonZero; i >= 0; i--) {
            printf("%d", sum[i]);
        }
    }
}

7-15 计算圆周率*

根据下面关系式,求圆周率的值,直到最后一项的值小于给定阈值。

2π​=1+31​+3×52!​+3×5×73!​+⋯+3×5×7×⋯×(2n+1)n!​+⋯

输入格式:

输入在一行中给出小于1的阈值。

输出格式:

在一行中输出满足阈值条件的近似圆周率,输出到小数点后6位。

输入样例:

0.01

输出样例:

3.132157

实现思路:

每次更新分子和分母的值,同时不断更新sum的值,直至分子除以分母小于给定的阈值

代码实现

#include 

int main() {
    double min;
    scanf("%lf",&min);
    double fz=1,fm=1,i=1,sum=1;
    while(fz/fm>min){
        fz=fz*i;
        fm=fm*(2*i+1);
        sum+=fz/fm;
        i++;    
    }
    printf("%.6lf",sum*2);
}


7-18 二分法求多项式单根*

二分法求函数根的原理为:如果连续函数f(x)在区间[a,b]的两个端点取值异号,即f(a)f(b)<0,则它在这个区间内至少存在1个根r,即f(r)=0。

二分法的步骤为:

  • 检查区间长度,如果小于给定阈值,则停止,输出区间中点(a+b)/2;否则
  • 如果f(a)f(b)<0,则计算中点的值f((a+b)/2);
  • 如果f((a+b)/2)正好为0,则(a+b)/2就是要求的根;否则
  • 如果f((a+b)/2)与f(a)同号,则说明根在区间[(a+b)/2,b],令a=(a+b)/2,重复循环;
  • 如果f((a+b)/2)与f(b)同号,则说明根在区间[a,(a+b)/2],令b=(a+b)/2,重复循环。

本题目要求编写程序,计算给定3阶多项式f(x)=a3​x3+a2​x2+a1​x+a0​在给定区间[a,b]内的根。

输入格式:

输入在第1行中顺序给出多项式的4个系数a3​、a2​、a1​、a0​,在第2行中顺序给出区间端点a和b。题目保证多项式在给定区间内存在唯一单根。

输出格式:

在一行中输出该多项式在该区间内的根,精确到小数点后2位。

输入样例:

3 -1 -3 1
-0.5 0.5

输出样例:

0.33

实现思路

本题我主要是没有明白那个小于给定的阈值什么意思,最后的输出是精确到小数点后两位,阈值可以取到0.001

代码实现

#include 
#include 

double a3, a2, a1, a0;
double f(double x) {
    return a3 * pow(x, 3) + a2 * pow(x, 2) + a1 * x + a0;
}

int main() {
    scanf("%lf %lf %lf %lf", &a3, &a2, &a1, &a0);
    double a, b;
    scanf("%lf %lf", &a, &b);
    while (b-a>0.001) {
        double mid = (a + b) / 2;
        double fmid = f(mid);
        if (f(a) * fmid > 0) {
            a = mid;
        }
        else if (f(b) * fmid > 0) {
            b = mid;
        }else if(fmid==0){
            break;
        }
    }
    printf("%.2lf\n", (a+b)/2);
    return 0;
}

7-23 币值转换**

输入一个整数(位数不超过9位)代表一个人民币值(单位为元),请转换成财务要求的大写中文格式。如23108元,转换后变成“贰万叁仟壹百零捌”元。为了简化输出,用小写英文字母a-j顺序代表大写数字0-9,用S、B、Q、W、Y分别代表拾、百、仟、万、亿。于是23108元应被转换输出为“cWdQbBai”元。

输入格式:

输入在一行中给出一个不超过9位的非负整数。

输出格式:

在一行中输出转换后的结果。注意“零”的用法必须符合中文习惯。

输入样例1:

813227345

输出样例1:

iYbQdBcScWhQdBeSf

输入样例2:

6900

输出样例2:

gQjB

实现思路

本题处理起来其实比较麻烦,需要考虑中间连续多0只输出一个0,末尾的零不输出,大于五位数一定会输出w,一个九位数可以进行分解,1(亿)  2345(2345万)  6789(6789),数字的万之间用一个数组进行映射,然后判断后续的输出

代码实现

#include 

int main() {
    int n;
    scanf("%d",&n);
    if(n==0){
        printf("a");return 0;
    }
    int num[10];int index=0;
    while(n){
        num[index]=n%10;
        index++;
        n=n/10;
    }
    int flag=0;
    //用于标记最后一个零出现的位置 
    for(int i=index-1;i>=0;i--){
        flag=0;
        while(num[i]==0){
            flag++;i--;
            if(num[i]!=0){
                i++;
                break;
            }
            if(i==0){
                i++;
                break;
            }
        }
    }
    char map[10]={'a','b','c','d','e','f','g','h','i','j'};
    for(int i=index-1;i>=0;i--){
        //中间有连续多0,只输出一个零 
        if(i>flag&&num[i]==0){
            while(num[i-1]==0){
                if(i==4){
                    printf("W");
                }
                i--;
            }
        } 
        //中间的正常输出
        if(i>flag)
        printf("%c",map[num[i]]);
        //末尾的0不输出
        else if(i<=flag&&num[i]!=0){
            printf("%c",map[num[i]]);
        }
        if(i==8){
            printf("Y");
        }else if((i==7&&num[i]!=0)||(i==3&&num[i]!=0)){
            printf("Q");
        }else if((i==6&&num[i]!=0)||(i==2&&num[i]!=0)){
            printf("B");
        }else if((i==5&&num[i]!=0)||(i==1&&num[i]!=0)){
            printf("S");
        }else if(i==4&&num[i]!=0){
            printf("W");
        }
    }
}

7-28 猴子选大王*

群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?

输入格式:

输入在一行中给一个正整数N(≤1000)。

输出格式:

在一行中输出当选猴王的编号。

输入样例:

11

输出样例:

7

实现思路

一个经典的约瑟夫问题,我喜欢用结构体,在结构体中用flag标识是否继续游戏,然后不断进行游戏,知道剩下最后一直猴子,输出它的id号

代码实现

#include 

typedef struct monkey{
    int id;
    int flag;
}monkey;

int main() {
    int n;
    scanf("%d",&n);
    monkey m[n];
    for(int i=0;in-1) i=0;
    }
    return 0;
}

7-29 删除字符串中的子串**

输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。

输入格式:

输入在2行中分别给出不超过80个字符长度的、以回车结束的2个非空字符串,对应S1和S2。

输出格式:

在一行中输出删除字符串S1中出现的所有子串S2后的结果字符串。

输入样例:

Tomcat is a male ccatat
cat

输出样例:

Tom is a male 

实现思路

这道题是很不错的一道题,用指针操作很方便很多,用strstr()函数循环判断,直到s1字符串中不包含s2字符串。如果有,用指针记录下返回的地址,指针后移s2的长度个单位。

代码实现

#include
#include 

int main(){
    char s1[81],s2[81];
    gets(s1);gets(s2);
    char* p;
    while(strstr(s1,s2)!=NULL){
        p=strstr(s1,s2);
        while(*p!='\0'){
            *p=*(p+strlen(s2));
            p++; 
        }
    }
    printf("%s",s1);
}

7-30 字符串的冒泡排序*

我们已经知道了将N个整数按从小到大排序的冒泡排序法。本题要求将此方法用于字符串序列,并对任意给定的K(

输入格式:

输入在第1行中给出N和K(1≤K

输出格式:

输出冒泡排序法扫描完第K遍后的中间结果序列,每行包含一个字符串。

输入样例:

6 2
best
cat
east
a
free
day

输出样例:

best
a
cat
day
east
free

实现思路

模拟冒泡排序的过程

代码实现

#include
#include

int main(){
    int n,k;
    scanf("%d %d",&n,&k);getchar();
    char s[n][11];
    for(int i=0;i0){
                char temp[11];
                strcpy(temp,s[j+1]);
                strcpy(s[j+1],s[j]);
                strcpy(s[j],temp);
            }
        }
    }
    for(int j=0;j

7-32 说反话-加强版**

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

输入格式:

测试输入包含一个测试用例,在一行内给出总长度不超过500 000的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母(大小写有区分)组成的字符串,单词之间用若干个空格分开。

输出格式:

每个测试用例的输出占一行,输出倒序后的句子,并且保证单词间只有1个空格。

输入样例:

Hello World   Here I Come

输出样例:

Come I Here World Hello

实现思路

逆序读入该字符串,以空格为分割,输出单词,空格不输出,每个单词输出后加上一个空格,注意判断第一个单词的位置,逆序输出的最后一个单词后面不加空格

代码实现

#include
#include

int main(){
    char s1[500002];
    gets(s1);
    int count=0;
    //标记第一个单词的位置
    int flag=0;
    for(int i=0;;i++){
        if(s1[i]!=' '){
            flag=i;
            break;
        }
    } 
    for(int i=strlen(s1)-1;i>=0;i--){
        count++;
        if(s1[i]==' '){
            for(int j=i+1;j

7-35 有理数均值**

本题要求编写程序,计算N个有理数的平均值。

输入格式:

输入第一行给出正整数N(≤100);第二行中按照a1/b1 a2/b2 …的格式给出N个分数形式的有理数,其中分子和分母全是整形范围内的整数;如果是负数,则负号一定出现在最前面。

输出格式:

在一行中按照a/b的格式输出N个有理数的平均值。注意必须是该有理数的最简分数形式,若分母为1,则只输出分子。

输入样例1:

4
1/2 1/6 3/6 -5/10

输出样例1:

1/6

输入样例2:

2
4/3 2/3

输出样例2:

1

实现思路

本题最开始的实现思路是,1.先找所有分母的最小公倍数,然后所有分子进行同分,变成同分母,分子,分母分别相加,然后找最大公约数进行化简(有一个测试点无法通过,这样做可能会导致溢出)

2.两个数相加,然后进行随时进行化简,循环实现,其他过程如上

代码实现

#include

//求最大公约数 
int max(int a,int b){
    while(b){
        int temp=b;
        b=a%b;
        a=temp;
    }
    return a;
}

//求最小公倍数
int minfun(int a,int b){
    return a*b/max(a,b);
} 

int main(){
    //输入过程 
    int n;
    scanf("%d",&n);
    int fz[n],fm[n];
    for(int i=0;i

7-36 复数四则运算**

本题要求编写程序,计算2个复数的和、差、积、商。

输入格式:

输入在一行中按照a1 b1 a2 b2的格式给出2个复数C1=a1+b1i和C2=a2+b2i的实部和虚部。题目保证C2不为0。

输出格式:

分别在4行中按照(a1+b1i) 运算符 (a2+b2i) = 结果的格式顺序输出2个复数的和、差、积、商,数字精确到小数点后1位。如果结果的实部或者虚部为0,则不输出。如果结果为0,则输出0.0。

输入样例1:

2 3.08 -2.04 5.06

输出样例1:

(2.0+3.1i) + (-2.0+5.1i) = 8.1i
(2.0+3.1i) - (-2.0+5.1i) = 4.0-2.0i
(2.0+3.1i) * (-2.0+5.1i) = -19.7+3.8i
(2.0+3.1i) / (-2.0+5.1i) = 0.4-0.6i

输入样例2:

1 1 -1 -1.01

输出样例2:

(1.0+1.0i) + (-1.0-1.0i) = 0.0
(1.0+1.0i) - (-1.0-1.0i) = 2.0+2.0i
(1.0+1.0i) * (-1.0-1.0i) = -2.0i
(1.0+1.0i) / (-1.0-1.0i) = -1.0

实现思路

输入实部和虚部,用两个数组分别存储实部和虚部加减乘除以后的结果(复数的计算公式),然后根据题目的要求进行输出

代码实现

#include
#include
int main()
{
	double a,b,c,d,x[5],y[5];
	scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
	x[0]=a+c;y[0]=b+d;
	x[1]=a-c;y[1]=b-d;
	x[2]=a*c-b*d;y[2]=b*c+a*d;
	x[3]=(a*c+b*d)/(c*c+d*d);y[3]=(b*c-a*d)/(c*c+d*d);
	char k[5]={'+','-','*','/'};
	for(int i=0;i<4;i++){
		if(fabs(x[i])<0.1&&fabs(y[i])<0.1){
			printf("(%.1f%+.1fi) %c (%.1f%+.1fi) = 0.0\n",a,b,k[i],c,d);
		}
		else if(fabs(x[i])<0.1){
			printf("(%.1f%+.1fi) %c (%.1f%+.1fi) = %.1fi\n",a,b,k[i],c,d,y[i]);
		}
		else if(fabs(y[i])<0.1){
			printf("(%.1f%+.1fi) %c (%.1f%+.1fi) = %.1f\n",a,b,k[i],c,d,x[i]);
		}
		else {
			printf("(%.1f%+.1fi) %c (%.1f%+.1fi) = %.1f%+.1fi\n",a,b,k[i],c,d,x[i],y[i]);
		}
	}
	return 0;
}


7-37 整数分解为若干项之和

将一个正整数N分解成几个正整数相加,可以有多种分解方法,例如7=6+1,7=5+2,7=5+1+1,…。编程求出正整数N的所有整数分解式子。

输入格式:

每个输入包含一个测试用例,即正整数N (0

输出格式:

按递增顺序输出N的所有整数分解式子。递增顺序是指:对于两个分解序列N1​={n1​,n2​,⋯}和N2​={m1​,m2​,⋯},若存在i使得n1​=m1​,⋯,ni​=mi​,但是ni+1​

输入样例:

7

输出样例:

7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7

实现思路

代码实现

7-38 数列求和-加强版*

给定某数字A(1≤A≤9)以及非负整数N(0≤N≤100000),求数列之和S=A+AA+AAA+⋯+AA⋯A(N个A)。例如A=1, N=3时,S=1+11+111=123。

输入格式:

输入数字A与非负整数N。

输出格式:

输出其N项数列之和S的值。

输入样例:

1 3

输出样例:

123

实现思路

模拟一个加法的过程,用一个动态数组存储(避免溢出)

代码实现

#include
#include
 
int main() {
	int a,n;
	scanf("%d %d",&a,&n);
	if(n==0){
	    printf("0");return 0;
    }
	char *num=(char*)malloc(sizeof(char)*10000000);
	*num=0;
	int index=0,up=0;
	while(n>0){
	    num[index]=((n*a)+up)%10;
	    up=((n*a)+up)/10;
	    index++;
	    n--;
    }
    while(up!=0){
        num[index]=up%10;
        up=((n*a)+up)/10;
        index++;
    }
    for(int i=index-1;i>=0;i--){
        printf("%d",num[i]);    
    }
	return 0;
}
 
 

你可能感兴趣的:(c语言,数据结构,算法)