2021寒假——洛谷刷题计划(35题)

(希望大家不要Copy)

  • AC:Accept,程序通过。
  • CE:Compile Error,编译错误。
  • PC:Partially Correct,部分正确。
  • WA:Wrong Answer,答案错误。
  • RE:Runtime Error,运行时错误。
  • TLE:Time Limit Exceeded,超出时间限制。
  • MLE:Memory Limit Exceeded,超出内存限制。
  • OLE:Output Limit Exceeded,输出超过限制。
  • UKE:Unknown Error,出现未知错误。

解决RE的方法:

  • 给所有变量赋初值0
  • 不用void,记得return 0
  • 数组开合适大小,建议习惯性开10000

防止segment fault:一些开的很大的数组,应设置为全局变量

如果程序过不了,尝试更改变量作用域等等…

P5705 数字反转

题目描述
输入一个不小于 100100 且小于 10001000,同时包括小数点后一位的一个浮点数,例如 123.4123.4 ,要求把这个数字翻转过来,变成 4.3214.321 并输出。
输入格式
一行一个浮点数
输出格式
一行一个浮点数

此代码未过关,修改中:

#include <stdio.h>
int Strlen(char str[]);
void StrReverse(char str[]);
//这里不需要考虑传入二级指针......

int main(){
	char str[32];
	fgets(str,32,stdin);
	StrReverse(str);
	printf("%s",str);
} 
int Strlen(char str[]){
	int i=0;
	while(str[i]!='\0')
		i++;
	return i;
}

void StrReverse(char str[]){
	int length=Strlen(str);
	//记录这个翻转字符串的关键算法
	char *p=str;
	char *q=str+length-1;
	char t;
	int i; 
	for(i=0;i<length/2;i++){
		t=*p;
		*p=*q;
		*q=t;
		//不需要考虑二级指针,只要这里用*p和*q就能改变原字符数组了
		p++;
		q--;
	}
}

过关代码:

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

int main(void)
{
    char str[32],*p,*q,t;
    int len;

    scanf("%31s",str);
    len = strlen(str);

    p=str,q=str+len-1;
    for(;p<q;p++,q--){
        t=*p;
        *p=*q;
        *q=t;
    }
    puts(str);
    return 0;
}

P6685 动态仙人掌(pow函数)

题目背景
众所周知,一场考试需要一道签到题。
题目描述
给定 n,mn,m,求有多少个正整数 xx,使得 x^m\le nx
m
≤n。
输入格式
一行两个正整数 n,mn,m。
输出格式
一个整数表示正整数 xx 的个数。

#include <stdio.h>
#include <math.h>
int main(void){
	int m,n,x=0;
	scanf("%d %d",&n,&m);
	while(pow(x,m)<=n)
		x++;
	//注意用pow函数,以及关注此处写法
	printf("%d",x-1);
	return 0;
} 

P1085 不高兴的津津

题目描述
津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。
输入格式
输入包括77行数据,分别表示周一到周日的日程安排。每行包括两个小于1010的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。
输出格式
一个数字。如果不会不高兴则输出00,如果会则输出最不高兴的是周几(用1, 2, 3, 4, 5, 6, 71,2,3,4,5,6,7分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。

#include<stdio.h>
int main(){
	int i,j,k,n;
	int a,b;
	int sum[7];
	int max;
	for(i=0;i<7;i++){
	//无需用到二维数组
		scanf("%d %d",&a,&b);
		sum[i]=a+b;
	}
	for(k=0,n=1;n<7;){
	//这里比较的过程,和选择排序一样
		if(sum[k]>=sum[n]){
			max=k;
			n++;
		}
		else{
			max=n;
			k=n;
			n++;
		}
	}
	printf("%d",max+1);
	return 0;
} 

P1055 ISBN 号码(strcat)

自己去洛谷看题

#include <stdio.h>
#include <string.h>
int main(){
	int i=0,sum=0,n=1,ans=0;
	char str[1024]={0};
	scanf("%s",str);
	int len=strlen(str);
	for(i=0;i<11;i++){
		if(str[i]!='-'){
			sum+=(str[i]-'0')*n;
			n++;
		}
		else continue;
	}
	ans=sum%11;
	if(ans!=10){
		if(ans==str[12]-'0') printf("Right");
		else{
			char num[4]={0};
			char newstr[1024]={0};
			char *p1=str,*p2=num;
			sprintf(num,"%d",ans);
			for(i=0;i<len-1;i++)
				newstr[i]=str[i];
			strcat(newstr,num);
			printf("%s",newstr);
		}		
	}
	else{
		if(str[12]=='X') printf("Right");
		else{
			char alpha[4]="X";
			char newstr[1024]={0};
			char *p1=str,*p2=alpha;
			for(i=0;i<len-1;i++)
				newstr[i]=str[i];
			strcat(newstr,alpha);
			printf("%s",newstr);
		}
	}
	return 0; 
}

P1980 计数问题(sprintf)

题目描述
试计算在区间 11 到 nn的所有整数中,数字x(0 ≤ x ≤ 9)x(0≤x≤9)共出现了多少次?例如,在 11到1111中,即在 1,2,3,4,5,6,7,8,9,10,111,2,3,4,5,6,7,8,9,10,11 中,数字 11 出现了 44 次。
输入格式
22个整数n,xn,x,之间用一个空格隔开。
输出格式
11个整数,表示xx出现的次数。

#include <stdio.h>
#include <stdlib.h>
int main(){
	int n,x;
	scanf("%d %d",&n,&x);
	int i,j,count=0;
	char str[102400];
	for(i=1;i<=n;i++){
		//itoa(i,str,10);
		//在洛谷不支持
		sprintf(str,"%d",i);
		//将数字转化成字符串存入str
		j=0;
		while(str[j]){
			if((str[j]-48)==x)
				count++;
			j++;
		}
	}
	printf("%d",count);
	return 0;
}

P1089 津津的储蓄计划(除法与取模)

题目描述
津津的零花钱一直都是自己管理。每个月的月初妈妈给津津300300元钱,津津会预算这个月的花销,并且总能做到实际花销和预算的相同。
为了让津津学习如何储蓄,妈妈提出,津津可以随时把整百的钱存在她那里,到了年末她会加上20%20%还给津津。因此津津制定了一个储蓄计划:每个月的月初,在得到妈妈给的零花钱后,如果她预计到这个月的月末手中还会有多于100100元或恰好100100元,她就会把整百的钱存在妈妈那里,剩余的钱留在自己手中。
例如1111月初津津手中还有8383元,妈妈给了津津300300元。津津预计1111月的花销是180180元,那么她就会在妈妈那里存200200元,自己留下183183元。到了1111月月末,津津手中会剩下33元钱。
津津发现这个储蓄计划的主要风险是,存在妈妈那里的钱在年末之前不能取出。有可能在某个月的月初,津津手中的钱加上这个月妈妈给的钱,不够这个月的原定预算。如果出现这种情况,津津将不得不在这个月省吃俭用,压缩预算。
现在请你根据2004年1月到12月每个月津津的预算,判断会不会出现这种情况。如果不会,计算到2004年年末,妈妈将津津平常存的钱加上20%还给津津之后,津津手中会有多少钱。
输入格式
1212行数据,每行包含一个小于350350的非负整数,分别表示11月到1212月津津的预算。
输出格式
一个整数。如果储蓄计划实施过程中出现某个月钱不够用的情况,输出-X−X,XX表示出现这种情况的第一个月;否则输出到20042004年年末津津手中会有多少钱。
注意,洛谷不需要进行文件输入输出,而是标准输入输出。

#include<stdio.h>
int main(){
        int i,expense,locMoney=0,num=0;
        for(i=1;i<=12;i++)
        {
                scanf("%d",&expense);
                locMoney=locMoney-expense+300;
                if(locMoney<0)
                {
                        printf("-%d",i);
                        return 0;
                }
                else num+=locMoney/100,locMoney%=100;
                //除法和取模值得学习
        }
        printf("%d",120*num+locMoney);
        return 0;
}

P2615 神奇的幻方(模拟)

【题目描述】
幻方是一种很神奇的 N*NN∗N 矩阵:它由数字 1,2,3,\cdots \cdots ,N \times N1,2,3,⋯⋯,N×N 构成,且每行、每列及两条对角线上的数字之和都相同。
当 NN 为奇数时,我们可以通过下方法构建一个幻方:
首先将 11 写在第一行的中间。
之后,按如下方式从小到大依次填写每个数 K (K=2,3,\cdots,N \times N)K(K=2,3,⋯,N×N) :
若 (K-1)(K−1) 在第一行但不在最后一列,则将 KK 填在最后一行, (K-1)(K−1) 所在列的右一列;
若 (K-1)(K−1) 在最后一列但不在第一行,则将 KK 填在第一列, (K-1)(K−1) 所在行的上一行;
若 (K-1)(K−1) 在第一行最后一列,则将 KK 填在 (K-1)(K−1) 的正下方;
若 (K-1)(K−1) 既不在第一行,也不在最后一列,如果 (K-1)(K−1) 的右上方还未填数,则将 KK 填在 (K-1)(K−1) 的右上方,否则将 KK 填在 (K-1)(K−1) 的正下方。
现给定 NN ,请按上述方法构造 N \times NN×N 的幻方。
【输入格式】
一个正整数 NN ,即幻方的大小。
【输出格式】
共 NN 行 ,每行 NN 个整数,即按上述方法构造出的 N \times NN×N 的幻方,相邻两个整数之间用单空格隔开。

#include <stdio.h>
int main(){
	int n=0,i=0,j=0,k=0,key=1,mid=0; 
	int c=0,r=0;
	scanf("%d",&n);
	int arr[128][128];
	int num[100000]={0};
	for(k=1;k<100000;k++)
		num[k]=key++;
	//将0到99999都存入数组 num 
	mid=(n-1)/2;
	arr[0][mid]=1;
	r=0,c=mid;
	//表示出上一个数的位置,0表示第一行或第一列 
	//此处初始化,1的位置在第一行中间 
	for(k=2;num[k]<=n*n;k++){
		if(r==0&&c!=n-1){
			arr[n-1][c+1]=num[k];
			r=n-1;
			c=c+1;
		}
		else if(r!=0&&c==n-1){
			arr[r-1][0]=num[k];
			r=r-1;
			c=0;
		}
		else if(r==0&&c==n-1){
			arr[1][n-1]=num[k];
			r=1;
			c=n-1;
		}
		else if(r!=0&&c!=n-1){
			if(!arr[r-1][c+1]){
				arr[r-1][c+1]=num[k];
				r=r-1;
				c=c+1;
			}
			else{
				arr[r+1][c]=num[k];
				r=r+1;				
			}
		}
	}
	for(i=0;i<n;i++)
		for(j=0;j<n;j++)
			printf("%d%c", arr[i][j], (j + 1 == n) ? '\n' : ' ');
	return 0;
}

P5723 质数口袋(循环)

题目描述
小 A 有一个质数口袋,里面可以装各个质数。他从 22 开始,依次判断各个自然数是不是质数,如果是质数就会把这个数字装入口袋。口袋的负载量就是口袋里的所有数字之和。但是口袋的承重量有限,不能装得下总和超过 L的质数。给出 L,请问口袋里能装下几个质数?将这些质数从小往大输出,然后输出最多能装下的质数个数,所有数字之间有一空行。

输入格式
一行一个正整数 L。

输出格式
将这些质数从小往大输出,然后输出最多能装下的质数个数,所有数字之间有一空行。

#include <stdio.h>
int main(){
	int prime[100001]={0};
	int limit=0,sum=0,count=0,x=0,y=0,k=0,i=0;
	scanf("%d",&limit);
	if(limit==1) limit=0;
	for(x=2;x<=100001;x++){
		for(y=2;y<=50001;y++){
			if(x%y==0) count++;
			if(count>1||x<y) break;
		}
		if(count==1) {
			prime[k++]=x;
			sum+=x;
			if(sum>limit){
				sum-=x;
				prime[--k]=0;
				break;
				//由于多计了一个数,在这里被卡了一会
			}			
		}
		count=0;
	}
	for(i=0;i<k;i++)
		printf("%d\n",prime[i]);
	printf("%d",k);
	return 0;
}

P1015 回文数(高精度,函数修改实参)

题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。

例如:给定一个十进制数 5656,将 5656 加 6565(即把 5656 从右向左读),得到 121121 是一个回文数。

又如:对于十进制数 8787:

STEP1:87+78=16587+78=165
STEP2:165+561=726165+561=726
STEP3:726+627=1353726+627=1353
STEP4:1353+3531=48841353+3531=4884

在这里的一步是指进行了一次 NN 进制的加法,上例最少用了 44 步得到回文数 48844884。

写一个程序,给定一个 NN(2 \le N \le 102≤N≤10 或 N=16N=16)进制数 MM(100100 位之内),求最少经过几步可以得到回文数。如果在 3030 步以内(包含 3030 步)不可能得到回文数,则输出 Impossible!。

输入格式
两行,分别是 NN,MM。

输出格式
如果能在 3030 步以内得到回文数,输出格式形如 STEP=ans,其中 ansans 为最少得到回文数的步数。

否则输出 Impossible!。
函数修改实参:先声明一个指针(假设int p=&num)指向要修改的数,然后把指针传入函数,在函数内,对p进行操作,就可以修改num的值

#include <stdio.h>
#include <string.h>
int arr[1000001]={0},revarr[1000001]={0};
char str[1000001]={0};

void GJAdd(int arr[],int revarr[],int *plen,int n){
//高精度,注意函数修改实参
	int i=0;
	for(i=0;i<=*plen;i++){
		arr[i]+=revarr[i];
		arr[i+1]+=arr[i]/n;
		arr[i]%=n;
	}
	if(arr[*plen+1]>0) (*plen)++;
	return;		
}

void Rev(int arr[],int revarr[],int len){
//逆序
	int i=0,j=0;
	for(i=len;i>0;i--)
		revarr[++j]=arr[i];	
	return;
}

int Judge(int arr[],int len){
//判断是否回文
	int ln=len,i=1,j=len;
	while(ln/2){
		ln--;
		if(arr[i++]!=arr[j--])
			return 0;
	}
	return 1;
}

void Init(){
//初始化
	int j=0,i=0;
	for(i=strlen(str)-1;i>=0;i--){
		if(str[i]>='0'&&str[i]<='9')
			arr[++j]=str[i]-'0';
		else
			arr[++j]=str[i]-'A'+10;
	}
	return;
}
int main(){
	int ans=0,n=0,num=0,i=0;
	scanf("%d\n",&n);
	scanf("%s",str);
	//洛谷不要用getchar()
	int len=strlen(str);
	int *plen=&len;
	Init();
	while(!Judge(arr,len)&&ans<30){
	//竟然忘了判断ans<30,我大意了啊
		ans++;
		Rev(arr,revarr,len);
		GJAdd(arr,revarr,plen,n);		
	}
	if(ans<30)
		printf("STEP=%d",ans);
	else printf("Impossible!");
	return 0;
}

P1098 字符串的展开(多情况模拟)

原题略,直接去洛谷搜题号吧

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int p1=0,p2=0,p3=0;
char str[1024]={0};
int PrintStr(char l,char r){
	char i=0;
	int n=0;
	if(l>=r||(isdigit(l)&&isalpha(r))||(isdigit(r)&&isalpha(l)))
		printf("-");
	else if(l+1==r)	return 0;
	else{
		if(isalpha(l)){
			if(p1==1){
				//变小写 
				l=tolower(l);
				r=tolower(r);
			}
			else if(p1==2){
				//变大写 
				l=toupper(l);
				r=toupper(r);
			}
		}
		if(p3==1){
			//正序 
			for(i=l+1;i<r;i++){
				for(n=0;n<p2;n++)
				//输出p2个 
					printf("%c",(p1==3)?'*':i);
			}
		}
		else if(p3==2){
			//逆序 
			for(i=r-1;i>l;i--)
			//又把l和1看错了,我勒个去......
				for(n=0;n<p2;n++)
				//输出p2个 
					printf("%c",(p1==3)?'*':i);
		}
	} 
}
int main(){
	scanf("%d%d%d",&p1,&p2,&p3);
	scanf("%s",str);
	char l=0;
	int i=0,start=0,len=strlen(str);
	//判断开头的'-' 
	for(i=0;i<len;i++){
		if(str[i]=='-')	printf("-");
		else{
			start=i;
			break;
		}
	}
	//对于剩余字符 
	for(i=start;i<len;i++){
		if(str[i]!='-')	printf("%c",str[i]);
		else if(i+1==len||(i+1!=len&&str[i+1]=='-')||l=='-') printf("-");
		else PrintStr(l,str[i+1]);
		l=str[i];	
	}
	return 0;
}

P1079 Vigenère 密码(分类,模运算处理循环)

原题去洛谷

#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(){
	char key[101]={0},psg[1001]={0},newpsg[1001]={0};
	int newkey[101]={0};
	int i=0;
	scanf("%s",key);
	scanf("%s",psg);
	int len1=strlen(key),len2=strlen(psg);
	for(i=0;i<len1;i++){
		key[i]=tolower(key[i]);
		newkey[i]=key[i]-'a';
	}
	for(i=0;i<len2;i++)
		if(psg[i]>='a'&&psg[i]<='z'&&psg[i]-newkey[i%len1]>='a')
			newpsg[i]=psg[i]-newkey[i%len1];
		else if(psg[i]>='a'&&psg[i]<='z'&&psg[i]-newkey[i%len1]<'a') 
			newpsg[i]=psg[i]-newkey[i%len1]+26;
		else if(psg[i]>='A'&&psg[i]<='Z'&&psg[i]-newkey[i%len1]>='A')
			newpsg[i]=psg[i]-newkey[i%len1];
		else newpsg[i]=psg[i]-newkey[i%len1]+26;
	printf("%s",newpsg);
	return 0;
}

P1124 文件压缩(找规律)

一开始会错意,把题目倒过来了,违背了原题初衷:

#include <stdio.h>
#include <string.h>
//题目要求它的逆过程 
int BubbleSort(char str[1024][1024],int len)
{
	int i=0,j=0;
	for(i=1;i<len;i++)
		for(j=0;j<len-i;j++)
			if(str[j][0]>str[j+1][0]){
				char tempstr[1024]={0};
				strcpy(tempstr,str[j]);
				strcpy(str[j],str[j+1]);
				strcpy(str[j+1],tempstr);
				//在二维数组中交换字符串的方式
			}
	return 0;
} 
int main(){
	int len=0,i=0,j=0,k=0,p=0,n=0;
	scanf("%d",&len);
	char str[1024][1024]={0};
	scanf("%s",str[0]);
	scanf("%d",&p);
	for(i=1;i<len;i++){
		char tmpstr[1024]={0};
		char *p=&str[0][i];
		strcpy(tmpstr,p);
		int tmplen=strlen(tmpstr);
		for(j=0;j<len-tmplen;j++)
			tmpstr[tmplen+j]=str[0][j];
		strcpy(str[i],tmpstr);
	}
	BubbleSort(str,len);
	char ans[1024]={0};
	for(k=0;k<len;k++)
		ans[k]=str[k][p-1];
	for(k=0;k<len;k++)
		printf("%s\n",str[k]);
	return 0;
} 

在这里插入图片描述
(参考这道题下的题解,总之可以一直找到example)

题目正确的代码:
(因为偷懒,暂时没看代码的逻辑)

#include <stdio.h>
char s[1000001]={0},ans[1000001]={0};	
int n=0,p=0,i=0;
int a[26]={0},l[26]={0},r[26]={0};
//不知道为什么,设置成全局变量后才能通过洛谷评测
int main(){
	scanf("%d%s%d",&n,s+1,&p);
	for(i=1;i<=n;i++) a[s[i]-'a']++;
	for(i=0;i<26;i++){
		l[i]=r[i-1]+1;
		r[i]=l[i]+a[i]-1;
	}
	int now=l[s[p]-'a'];
	int tot=0;
	while(tot<n){
		ans[tot]=s[now];
		now=r[s[now]-'a']--;
		tot++;
	}
	for(i=n-1;i>=0;i--) printf("%c",ans[i]);
	return 0;
} 

P1059 明明的随机数(桶排序)

题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了NN个11到10001000之间的随机整数(N≤100)(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
输入格式
输入有两行,第11行为11个正整数,表示所生成的随机数的个数NN
第22行有NN个用空格隔开的正整数,为所产生的随机数。
输出格式
输出也是两行,第11行为11个正整数MM,表示不相同的随机数的个数。
第22行为MM个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

方法一:分别写出去重函数和qsort排序

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

int arraylen(int array[]){
	int i=0;
	for(i=0;array[i];i++);
	return i;
}

int RemoveDuplicate(int array[],int newarr[]){
	int r=0,w=0,i=0,j=0,len=0,count=0;
	len=arraylen(array);
	for(r=w=0;r<len;r++){
		if(array[r]){
			array[w++]=array[r];
			for(i=r+1;i<len;i++){
				if(array[r]==array[i]){
					array[i]=0;
					count++;					
				}
			}
		}
	}
	for(j=0;j<len-count;j++){
		newarr[j]=array[j];
	}
	return count;
}

int cmp(const void *a, const void *b)
{
	return ( *(int*)a - *(int*)b );
}
int sort(int array[],int n){
	qsort(array,n, sizeof(int),cmp);
	return 0;
}

int main(){
	int n=0,i=0,len=0,count=0;
	int array[3200];
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&array[i]);
	int newarr[3200];
	len=arraylen(array);
	count=RemoveDuplicate(array,newarr);
	sort(newarr,len-count);
	printf("%d\n",len-count);
	for(i=0;i<len-count;i++)
		printf("%d ",newarr[i]);	
	return 0; 
}

方法二:桶排序(推荐)

桶排序的思路比较简单,不再赘述。

#include <stdio.h>
int BucketArr(int arr[],int n){
	int i=0,j=0,count=0;
	int num[10000]={0};
	for(i=0;i<n;i++){
		if(arr[i]&&!num[arr[i]])
		//注意此处是num[arr[i]],容易写错
		{
			num[arr[i]]++;
			count++;		
		}
	}
	printf("%d\n",count);
	for(j=0;j<10000;j++){
		if(num[j])
			printf("%d ",j);
	}
	return 0;
}
int main(){
	int n=0,i=0;
	int arr[10000]={0};
	scanf("%d",&n);
	for(i=0;i<n;i++){
		scanf("%d",&arr[i]);
	}
	BucketArr(arr,n);
	return 0;
} 

P1068 分数线划定(结构体排序)

题目描述
世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,AA市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%150%划定,即如果计划录取mm名志愿者,则面试分数线为排名第m \times 150%m×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。

现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。

输入格式
第一行,两个整数 n,m(5 ≤ n ≤ 5000,3 ≤ m ≤ n)n,m(5≤n≤5000,3≤m≤n),中间用一个空格隔开,其中nn表示报名参加笔试的选手总数,mm表示计划录取的志愿者人数。输入数据保证 m \times 150%m×150%向下取整后小于等于 nn。

第二行到第 n+1n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号 k(1000 ≤ k ≤ 9999)k(1000≤k≤9999)和该选手的笔试成绩s(1 ≤ s ≤ 100)s(1≤s≤100)。数据保证选手的报名号各不相同。

输出格式
第一行,有22个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。

从第二行开始,每行包含22个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。

#include <stdio.h>
typedef struct stu{
	int num;
	int mark;
}stu;
void StructSort(stu arr[],int n){
	stu temp;
	int i=0,j=0;
	for(i=1;i<n;i++){
		for(j=0;j<n-i;j++){
			if(arr[j].mark<arr[j+1].mark){
				temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;					
			}
			else if(arr[j].mark==arr[j+1].mark&&arr[j].num>arr[j+1].num){
				temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;					
			}	
		}		
	}
	return;
}
int main(){
	int n=0,m=0,M=0,i=0,j=0,markline=0;
	//n是选手总数,m是计划录取人数,M是进入面试人数 
	scanf("%d %d",&n,&m);
	stu stus[51200];
	for(i=0;i<n;i++)
		scanf("%d %d",&stus[i].num,&stus[i].mark);
	StructSort(stus,n);
	M=m*3/2;
	markline=stus[M-1].mark;
	for(j=M;j<n;j++)
		if(stus[j].mark==markline)
			M++;
	printf("%d %d\n",markline,M);
	for(i=0;i<M;i++)
		printf("%d %d\n",stus[i].num,stus[i].mark);
	return 0;
} 

P1093 奖学金(结构体排序)

题目描述
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。

任务:先根据输入的3门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名名学生的学号和总分。注意,在前5名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:

77 279279
55 279279

这两行数据的含义是:总分最高的两个同学的学号依次是77号、55号。这两名同学的总分都是 279279 (总分等于输入的语文、数学、英语三科成绩之和) ,但学号为77的学生语文成绩更高一些。如果你的前两名的输出数据是:

55 279279
77 279279

则按输出错误处理,不能得分。

输入格式
共n+1行。

第11行为一个正整数n( \le 300)n(≤300),表示该校参加评选的学生人数。

第22到n+1n+1行,每行有33个用空格隔开的数字,每个数字都在00到100100之间。第jj行的33个数字依次表示学号为j-1j−1的学生的语文、数学、英语的成绩。每个学生的学号按照输入顺序编号为1~n1 n(恰好是输入数据的行号减11)。

所给的数据都是正确的,不必检验。

//感谢 黄小U饮品 修正输入格式

输出格式
共5行,每行是两个用空格隔开的正整数,依次表示前55名学生的学号和总分。

#include <stdio.h>
typedef struct stu{
	int num;
	int Chi;
	int math;
	int Eng;
	int score;
	//结构体内的成员不可以初始化为0,会报错
}stu;

int StructSort(stu arr[],int n){
	stu temp;
	int i=0,j=0;
	for(i=1;i<n;i++)
		for(j=0;j<n-i;j++)
			if(arr[j].score<arr[j+1].score){
				temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
			}
			//使用冒泡排序比较总成绩,总成绩相同则比较语文成绩
			else if(arr[j].score==arr[j+1].score){
				if(arr[j].Chi<arr[j+1].Chi){
					temp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;					
				}
			}
}
int main(){
	int n=0,i=0,j=0;
	stu arr[3200];
	//数组开小会RE
	scanf("%d",&n);
	for(i=0;i<n;i++){
		arr[i].num=i+1;
		scanf("%d %d %d",&arr[i].Chi,&arr[i].math,&arr[i].Eng);
		arr[i].score=arr[i].Chi+arr[i].math+arr[i].Eng;
	}
	StructSort(arr,n);
	for(j=0;j<5;j++)
		printf("%d %d\n",arr[j].num,arr[j].score);
	return 0;
}

P1328 生活大爆炸版石头剪刀布(switch)

游戏规则含图片,直接附上题目链接:这儿

题目不难,用switch可以少用一些if

#include <stdio.h>
int main(){
	int n=0,t1=0,t2=0,score1=0,score2=0;
	int i=0,j=0,k=0;
	int T1[256]={0};
	int T2[256]={0};
	scanf("%d %d %d",&n,&t1,&t2);
	for(i=0;i<t1;i++)
		scanf("%d",&T1[i]);
	for(j=0;j<t2;j++){
		scanf("%d",&T2[j]);
	}
	for(k=0;k<n;k++){
		int p=k,q=k;
		if(p>=t1) p%=t1;
		if(q>=t2) q%=t2;
		if(T1[p]==0){
			switch(T2[q]){
				case 0:break;
				case 1:score2++;break;
				case 2:score1++;break;
				case 3:score1++;break;
				case 4:score2++;break;	
			}
		}
		else if(T1[p]==1){
			switch(T2[q]){
				case 0:score1++;break;
				case 1:break;
				case 2:score2++;break;
				case 3:score1++;break;
				case 4:score2++;break;	
			}
		}
		else if(T1[p]==2){
			switch(T2[q]){
				case 0:score2++;break;
				case 1:score1++;break;
				case 2:break;
				case 3:score2++;break;
				case 4:score1++;break;
			}
		}
		else if(T1[p]==3){
			switch(T2[q]){
				case 0:score2++;break;
				case 1:score2++;break;
				case 2:score1++;break;
				case 3:break;
				case 4:score1++;break;
			}
		}
		else if(T1[p]==4){
			switch(T2[q]){
				case 0:score1++;break;
				case 1:score1++;break;
				case 2:score2++;break;
				case 3:score2++;break;
				case 4:break;
			}
		}
	}
	printf("%d %d",score1,score2);
	return 0;
} 

P1003 铺地毯(模拟)

题目描述
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 nn 张地毯,编号从 11 到 nn。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。


地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

输入格式
输入共 n + 2n+2 行。

第一行,一个整数 nn,表示总共有 nn 张地毯。

接下来的 nn 行中,第 i+1i+1 行表示编号 ii 的地毯的信息,包含四个整数 a ,b ,g ,ka,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标 (a, b)(a,b) 以及地毯在 xx 轴和 yy 轴方向的长度。

第 n + 2n+2 行包含两个整数 xx 和 yy,表示所求的地面的点的坐标 (x, y)(x,y)。

输出格式
输出共 11 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出 -1。

这估计是我做得最顺的一道题

#include <stdio.h>
typedef struct M{
	int a;
	int b;
	int g;
	int k;
}M;
int main(){
	int n=0,x=0,y=0,i=0,j=0,ans=-1;
	M arr[100001];
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d %d %d %d",&arr[i].a,&arr[i].b,&arr[i].g,&arr[i].k);
	scanf("%d %d",&x,&y);
	for(j=0;j<n;j++){
		if((arr[j].a<=x&&(arr[j].a+arr[j].g)>=x)&&(arr[j].b<=y&&(arr[j].b+arr[j].k)>=y))
			ans=j+1;
	}
	printf("%d",ans);
	return 0;
}

P2392 kkksc03考前临时抱佛脚(dp,01背包)

求复习最短时间

该题解已搞懂

#include <stdio.h>
int a[5],i,j,k,sum,t,homework[21],dp[2501];
int max(int a,int b){
	if(a>=b) return a;
	else return b;
}
int main(){
	for(i=1;i<=4;i++)
		scanf("%d",&a[i]);
	for(i=1;i<=4;i++){
		sum=0;
		for(j=1;j<=a[i];j++){
			scanf("%d",&homework[j]);
			sum+=homework[j];
			//算出总时间 
		}
		for(j=1;j<=a[i];j++)
			for(k=sum/2;k>=homework[j];k--)
			//01背包
				dp[k]=max(dp[k],dp[k-homework[j]]+homework[j]);
		t+=sum-dp[sum/2];
		for(j=1;j<=sum/2;j++)
			dp[j]=0;
	}
	printf("%d",t);
	return 0;
} 

P1036 选数(DFS变体,素数)

题目:kokodayo

#include <stdio.h>
int n,k,ans,a[1024];
int isprime(int a){
	for(int i=2;i*i<=a;i++)
		if(a%i==0) return 0;
	return 1;	
}
void dfs(int m,int sum,int startx){
	if(m==k){
		if(isprime(sum)) ans++;		
		return;
	}
	for(int i=startx;i<n;i++)
		dfs(m+1,sum+a[i],i+1);
	return;
	/*这里dfs函数执行的过程像是一个n叉树(在纸上画一画就能明白)
	*它遍历的范围超过了要找的所有情况的组合
	*有些分支可以一直走下去,找到正确的加和
	
	*而有些分支,比如样例的数据:4 3 n\ 3 7 12 19
	*第一次进入dfs函数,从for循环的最后一次递归dfs,即dfs(1,a[3],4)
	*再进入新的for循环,int i=4,不满足i<n直接离开for循环,终止
	*/
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	dfs(0,0,0);
	printf("%d\n",ans);
	return 0;
}

P1076 寻宝(模拟*)

题目描述
传说很遥远的藏宝楼顶层藏着诱人的宝藏。小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。说明书的内容如下:

藏宝楼共有N+1N+1层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。除了顶层外,藏宝楼另有NN层,每层MM个房间,这MM个房间围成一圈并按逆时针方向依次编号为0,…,M-10,…,M−1。其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。每个房间里有一个指示牌,指示牌上有一个数字xx,表示从这个房间开始按逆时针方向选择第xx个有楼梯的房间(假定该房间的编号为k),从该房间上楼,上楼后到达上一层的kk号房间。比如当前房间的指示牌上写着22,则按逆时针方向开始尝试,找到第22个有楼梯的房间,从该房间上楼。如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。

寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。

请帮助小明算出这个打开宝箱的密钥。

输入格式
第一行22个整数NN和MM,之间用一个空格隔开。NN表示除了顶层外藏宝楼共NN层楼,MM表示除顶层外每层楼有MM个房间。

接下来N \times MN×M行,每行两个整数,之间用一个空格隔开,每行描述一个房间内的情况,其中第(i-1) \times M+j(i−1)×M+j行表示第ii层j-1j−1号房间的情况(i=1,2,…, Ni=1,2,…,N;j=1,2,…,Mj=1,2,…,M)。第一个整数表示该房间是否有楼梯通往上一层(00表示没有,11表示有),第二个整数表示指示牌上的数字。注意,从jj号房间的楼梯爬到上一层到达的房间一定也是jj号房间。

最后一行,一个整数,表示小明从藏宝楼底层的几号房间进入开始寻宝(注:房间编号从00开始)。

输出格式
一个整数,表示打开宝箱的密钥,这个数可能会很大,请输出对2012320123取模的结果即可。

我的答案,超时:

#include <stdio.h>
typedef struct room{
	int a;
	int b;
}room;
int N=0,M=0,i=0,j=0,k=0,sum=0,ans=0,start=0;
room arr[10001][101];
//开的很大的数组要设置为全局变量,否则会segment fault
int main(){
	scanf("%d %d",&N,&M);
	for(i=0;i<N;i++)
		for(j=0;j<M;j++)
			scanf("%d %d",&arr[i][j].a,&arr[i][j].b);
	scanf("%d",&start);
	for(i=0;i<N;i++){
		sum+=arr[i][start].b;
		if(i==N-1) break;
		int newstart=start;
		while(k!=arr[i][start].b){
			if(arr[i][newstart].a==1) k++;
			if(k!=arr[i][start].b){
				newstart++;
				newstart%=M;					
			}
		}
		start=newstart;
	}
	ans=sum%20123;
	printf("%d",ans);
	return 0;
}

正解,可惜我看的不太懂

#include <stdio.h>
int n,m,i,j,a[10010][110],num[10010][110],key,location;
int main(){
	scanf("%d %d",&n,&m);
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++){
			scanf("%d%d",&a[i][j],&num[i][j]);
			if(a[i][j])	a[i][0]++;
			//a[i][0]储存本层有多少楼梯通往上一层 
		}
	scanf("%d",&location);
	location+=1;
	for(i=1;i<=n;i++){
		key+=num[i][location];
		int x=num[i][location]%a[i][0]+a[i][0];
		//重点
		location--;
		while(x){
			location++;
			if(location>m) location=1;//回到第一个 
			if(a[i][location]) x--; 
		}
	}	
	printf("%d",key%20123);
	return 0;
} 

P1952 火星上的加法运算(完善高精度)

题目描述
最近欢欢看到一本有关火星的书籍,其中她被一个加法运算所困惑,由于她的运算水平有限.她想向你求助,作为一位优秀的程序员,你当然不会拒绝。
输入格式
第一行先输入一个运算的进制N(2<=N<=36),接下来两行为需要进行运算的字符,其中每个字符串的长度不超过200位,其为N进制的数。其中包括0-9及a-z(代表10-35)。
输出格式
在N进制下它们的和

这道题目是典型的高精度,相较于其他几道题

#include <stdio.h>
#include <string.h>
char str1[102400],str2[102400];
int arr1[102400],arr2[102400];
int max(int a,int b){
	if(a>=b) return a;
	else return b;
}
void Init(char str[],int arr[]){
	int j=0,i=0;
	for(i=strlen(str)-1;i>=0;i--){
		if(str[i]>='0'&&str[i]<='9')
			arr[++j]=str[i]-'0';
		else
			arr[++j]=str[i]-'a'+10;
	}
	return;
}
void GJAdd(int arr1[],int arr2[],int *plen,int n){
	int i=0;
	for(i=0;i<=*plen;i++){
		arr1[i]+=arr2[i];
		arr1[i+1]+=arr1[i]/n;
		arr1[i]%=n;
	}
	if(arr1[*plen+1]>0) (*plen)++;
	return;		
}
//以上三个函数,我愿称之为高精三剑客

int main(){
	int i=0,n=0;
	scanf("%d",&n);
	scanf("%s %s",str1,str2);
	Init(str1,arr1);
	Init(str2,arr2);
	
	int len1=strlen(str1);
	int len2=strlen(str2);
	int len=max(len1,len2);
	//注意这一步是必须的,否则会WA
	
	int *plen=&len;
	GJAdd(arr1,arr2,plen,n);
	for(i=len;i>=1;i--){
		if(arr1[i]>=10) printf("%c",arr1[i]+87);
		else printf("%c",arr1[i]+48);		
	}

	return 0;
}

P1101 单词方阵(DFS)

题目描述
给一n \times nn×n的字母方阵,内可能蕴含多个“yizhong”单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 88 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用*代替,以突出显示单词。
输入格式
第一行输入一个数nn。(7 \le n \le 1007≤n≤100)。

第二行开始输入n \times nn×n的字母矩阵。

输出格式
突出显示单词的n \times nn×n矩阵。

DFS:深度优先搜索

#include <stdio.h>
int DFS(int x,int y,int n,char arr[128][128],char newarr[128][128]){
//传参数时,二维数组第一个[]必须传值
	int i=0,flag=1,j=1,k=0,count=0;
	const int dx[]={1,1,1,0,0,-1,-1,-1};
	const int dy[]={1,0,-1,1,-1,0,1,-1};
	//组合成八个方向的向量
	const char str[]="yizhong";
	for(i=0;i<8;i++){
		for(j=1;j<=6;j++){
			int nx=x+j*dx[i];
			int ny=y+j*dy[i];
			if(nx<0||nx>n||ny<0||ny>n){
				break;
				//越界
			}
			if(str[j]!=arr[nx][ny]){
				break;
				//不匹配
			}
			count++;
			if(count==6){
				newarr[x][y]=arr[x][y];
				for(k=0;k<=6;k++){
					int nx=x+k*dx[i];
					int ny=y+k*dy[i];
					newarr[nx][ny]=arr[nx][ny];
					//将arr内的字符存入newarr
				}
				count=0;				
			}
		}
	} 	
	return 0;
}
int main(){
	int n=0,i=0,j=0,p=0,q=0,k=0,l=0,count=0;
	char arr[128][128]={0};
	char newarr[128][128]={0};
	scanf("%d",&n);
	for(i=0;i<n;i++){
			scanf("%s",&arr[i]);
	}
	for(p=0;p<n;p++){
		for(q=0;q<n;q++){
			if(arr[p][q]=='y') 
				DFS(p,q,n,arr,newarr);
		}
	}
	for(k=0;k<n;k++){
		for(l=0;l<n;l++){
			if(!newarr[k][l]){
				if(l+1!=n)	printf("*");
				else printf("*\n");
				//用三目运算符输出'\0',不知为何会输出空格,只能退而求其次				
			}
			else{
				if(l+1!=n)  printf("%c",arr[k][l]);
				else printf("%c\n", arr[k][l]);
			} 
		}
	}
	return 0;
}

P1596 Lake Counting S(DFS连通性问题)

题目描述
由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个NxM(1<=N<=100;1<=M<=100)网格图表示。每个网格中有水(‘W’) 或是旱地(’.’)。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。
输入格式
第1行:两个空格隔开的整数:N 和 M 第2行到第N+1行:每行M个字符,每个字符是’W’或’.’,它们表示网格图中的一排。字符之间没有空格。
输出格式
一行:水坑的数量

#include <stdio.h>
char arr[128][128]={0};
int flag[128][128]={0};
//用于判断单元格是否搜索过 
const int dx[]={1,1,1,0,0,-1,-1,-1};
const int dy[]={1,0,-1,1,-1,0,1,-1};
int DFS(int x,int y){
	int i=0,j=0;
	flag[x][y]=1;
	for(i=0;i<8;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if(arr[nx][ny]=='W'&&!flag[nx][ny])
			DFS(nx,ny);
	}
	return 0;	
}
int main(){
	int a=0,b=0,i=0,j=0,k=0,ans=0;
	scanf("%d %d",&a,&b);
	for(i=0;i<a;i++)
		scanf("%s",&arr[i]);
	for(j=0;j<a;j++){
		for(k=0;k<b;k++){
			if(arr[j][k]=='W'&&!flag[j][k]){
				DFS(j,k);
				ans++;
				//ans是answer的缩写
			}
		}			
	}
	printf("%d",ans);
	return 0;
} 

这道题还可以用BFS(广度优先搜索),本蒟蒻太懒先搁着…

P1123 取数游戏(DFS+复杂递归)

题目描述
一个N×M的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻8个格子中的一个即认为这两个数字相邻),求取出数字和最大是多少。

输入格式
第1行有一个正整数T,表示了有T组数据。

对于每一组数据,第一行有两个正整数N和M,表示了数字矩阵为N行M列。

接下来N行,每行M个非负整数,描述了这个数字矩阵。

输出格式
T行,每行一个非负整数,输出所求得的答案。

#include <stdio.h>
/*每个数都有取和不取两种选择,
*在main函数中调用dfs函数压入栈底;
*第一次递归入dfs其实就是进了不取这个数的情况;
*当这个递归执行完后,原先接近栈底的函数继续执行,便是取这个数的情况;
*如果它没被标记,就取这个数并且标记它的周围,并且继续递归dfs;
*对于这个数,有时候因为取了它周围数的缘故,导致这它取不了;
*为了让所有数都能被取,一些数标记后应该回溯,去掉标记,
*这样在其他情况中它周围的数就能被取了。
*/ 
const int d[8][2]={1,0,-1,0,0,1,0,-1,1,1,-1,1,1,-1,-1,-1};
int t,n,m,s[8][8],mark[8][8],ans,mx;
int max(int a,int b){
	if(a>=b) return a;
	else return b;
}
void DFS(int x,int y){
	//y到边界(y为水平方向)搜索下一行 
	if(y==m+1){
		DFS(x+1,1);
		return;
	}
	//x到边界,搜索结束,刷新最大值 
	if(x==n+1){
		mx=max(ans,mx);
		return;
	}
	//不取此数的情况
	DFS(x,y+1);
	//取此数的情况 
	int fx;
	if(mark[x][y]==0){
		ans+=s[x][y];
		for(fx=0;fx<8;fx++) 
			mark[x+d[fx][0]][y+d[fx][1]]++;
		DFS(x,y+1);
		//回溯 
		for(fx=0;fx<8;fx++)
			mark[x+d[fx][0]][y+d[fx][1]]--;
		ans-=s[x][y];
	} 
	
}
int main(){
	int i,j;
	scanf("%d",&t);
	//用while会更加方便 
	while(t--){
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)
			for(j=1;j<=m;j++)
				scanf("%d",&s[i][j]);
		mx=0;
		DFS(1,1);
		printf("%d\n",mx);
	}
	return 0;
}

P1255 数楼梯(斐波拉契+高精度)

题目描述
楼梯有 NN 阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

输入格式
一个数字,楼梯数。

输出格式
输出走的方式总数。

为什么要用斐波拉契
也可以看这道题下边的题解,有一个题解讲原因讲得不错

#include <stdio.h>
int arr[5010][5010]={0},len=1;
int GJAdd(int k){
	int i=0;
	for(i=1;i<=len;i++)
		arr[k][i]=arr[k-1][i]+arr[k-2][i];
	for(i=1;i<=len;i++){
		if(arr[k][i]>9){
			arr[k][i+1]+=arr[k][i]/10;
			//高精度算法 
			//把高位放在右边 
			arr[k][i]%=10;
			if(arr[k][len+1]>0)len++;
		}
	}		
}
int main(){
	int n=0,i=0,j=0,k=0;
	arr[0][1]=0;
	arr[1][1]=1;
	arr[2][1]=2;  
	scanf("%d",&n);
	for(i=3;i<=n;i++)
		GJAdd(i);
	for(i=len;i>=1;i--){
		printf("%d",arr[n][i]);
		//输出时要逆序输出 
	}
	return 0;
}

P2437 蜜蜂路线

题目背景


题目描述
一只蜜蜂在下图所示的数字蜂房上爬动,已知它只能从标号小的蜂房爬到标号大的相邻蜂房,现在问你:蜜蜂从蜂房 m 开始爬到蜂房 n,m<n,有多少种爬行路线?

本题和上一题数楼梯是一样的,只是修改了部分变量

#include <stdio.h>
int arr[5010][5010]={0},len=1;
int GJAdd(int k){
	int i=0;
	for(i=1;i<=len;i++)
		arr[k][i]=arr[k-1][i]+arr[k-2][i];
	for(i=1;i<=len;i++){
		if(arr[k][i]>9){
			arr[k][i+1]+=arr[k][i]/10;
			//高精度算法 
			//把高位放在右边 
			arr[k][i]%=10;
			if(arr[k][len+1]>0)len++;
		}
	}		
}
int main(){
	int n=0,m=0,i=0,j=0,k=0;
	arr[0][1]=0;
	arr[1][1]=1;
	arr[2][1]=2;  
	scanf("%d%d",&n,&m);
	int div=m-n;
	for(i=3;i<=div;i++)
		GJAdd(i);
	for(i=len;i>=1;i--){
		printf("%d",arr[div][i]);
		//输出时要逆序输出 
	}
	return 0;
}

P1028 数的计算(递推)

题目描述
我们要求找出具有下列性质数的个数(包含输入的正整数 nn)。

先输入一个正整数 nn(n \le 1000n≤1000),然后对此正整数按照如下方法进行处理:

不作任何处理;

在它的左边加上一个正整数,但该正整数不能超过原数的一半;

加上数后,继续按此规则进行处理,直到不能再加正整数为止。

输入格式
11 个正整数 nn(n \le 1000n≤1000)

输出格式
11 个整数,表示具有该性质数的个数。

如果说递归时间复杂度较高,那么递推就是要用一些数学方法,找到规律,降低时间复杂度

#include <stdio.h>
int arr[1024];
int main(){
	int n,i;
	scanf("%d",&n);
	arr[1]=1;
	/*
	设f[i]为初始值为i时的满足条件总数,可得f[i]=f[1]+f[2]+f[3]+...+f[i/2];容易想到f[1]=1;
	因为f[i]=f[1]+f[2]+f[3]+...+f[i/2] 所以当i为奇数时f[i]=f[i-1],当i为偶数时f[i]=f[i-1]+f[i/2];
	*/
	for(i=2;i<=n;i++){
		arr[i]=arr[i-1];
		if(i%2==0) arr[i]+=arr[i/2];
	}
	printf("%d",arr[n]);
	return 0;
} 

P1164 小A点菜(典型dp,01背包)

题目:kokodayo

看到01背包问题,脑海中一定要有表

若钱充足,办法总数就等于吃这道菜的办法数与不吃这道菜的办法数之和;若不充足,办法总数就只能承袭吃前i-1道菜的办法总数。依次递推,在最后,我们只要输出f[n][m]的值即可。

#include <stdio.h>
int n,m;
int arr[101],way[101][10001];
//定义way[i][j]为用前i道菜花光j元钱的方法总数 
int main(){
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&arr[i]);
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			if(j==arr[i]) way[i][j]=way[i-1][j]+1;
			else if(j>arr[i]) way[i][j]=way[i-1][j]+way[i-1][j-arr[i]];
			else if(j<arr[i]) way[i][j]=way[i-1][j];
		}
	}
	printf("%d",way[n][m]);
	return 0;
} 

P2678 跳石头(二分)

题目在这

#include <stdio.h>
#define max 2000000
int n,a[max],m,left,right,l,s,num,mid,ans,i;
int half(int x){
//当前的理想距离是否满足条件,要去右边二分还是去左边二分 
	s=0,num=0;
	//num记录移走石头数目,s记录目前石头距离起点距离 
	for(i=1;i<=n+1;i++){
		if(a[i]-s<x) num++;
		else s=a[i];
	}
	if(num>m) return 0;
	//移走石块数>m才能到期望距离,不满足条件 
	return 1;
}
void bsearch(int left,int right){
	while(left<=right){
		mid=(left+right)/2;
		if(half(mid)){
			left=mid+1;
			ans=mid;
		}
		else right=mid-1;
	}
}
int main(){
	scanf("%d%d%d",&l,&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	a[n+1]=l;
	left=0,right=l;
	bsearch(left,right);
	printf("%d",ans);
	return 0;
} 

P1873 砍树(经典二分)

题目描述
伐木工人米尔科需要砍倒M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。

米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。

例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。

米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入格式
第1行:2个整数N和M,N表示树木的数量(1<=N<=1000000),M表示需要的木材总长度(1<=M<=2000000000)

第2行:N个整数表示每棵树的高度,值均不超过1000000000。所有木材长度之和大于M,因此必有解。

输出格式
第1行:1个整数,表示砍树的最高高度。

#include<stdio.h>
long long n,bz,sum,mid,shortest,longest,trees[1000008];
int max(int a,int b){
	if(a>=b) return a;
	else return b;
}
int main(){
	int i;
    scanf("%lld%lld",&n,&bz); 
    for(i=1;i<=n;i++){
        scanf("%lld",&trees[i]);
        longest=max(longest,trees[i]);
    }
    while(shortest<=longest){
    	sum=0;
        mid=(shortest+longest)/2;
        for(i=1;i<=n;i++) 
			if(trees[i]>mid)
				sum+=trees[i]-mid; 
				//高的部分累加 
        if(sum<bz)
		//木材不足 
			longest=mid-1;
			//在左边搜,减小高度增加木材 
		else 
			shortest=mid+1;
			//在右边搜,增加高度减小木材 
    }
    printf("%lld",shortest-1);
    return 0;
}

P1638 逛画展(双指针)

题目描述
博览馆正在展出由世上最佳的 M 位画家所画的图画。

wangjy想到博览馆去看这几位大师的作品。
可是,那里的博览馆有一个很奇怪的规定,就是在购买门票时必须说明两个数字,
a和b,代表他要看展览中的第 a 幅至第 b 幅画(包含 a 和 b)之间的所有图画,而门票
的价钱就是一张图画一元。

为了看到更多名师的画,wangjy希望入场后可以看到所有名师的图画(至少各一张)。
可是他又想节省金钱。。。
作为wangjy的朋友,他请你写一个程序决定他购买门票时的 a 值和 b 值。

输入格式
第一行是 N 和 M,分别代表博览馆内的图画总数及这些图画是由多少位名师的画
所绘画的。
其后的一行包含 N 个数字,它们都介于 1 和 M 之间,代表该位名师的编号。

输出格式
a和 b(a<=b) 由一个空格符所隔开。
保证有解,如果多解,输出a最小的。

#include <stdio.h>
int l = 1,r = 1;
int arr[1000001];
//存放画的序号 
int buc[2001];
//每一位画家对应一个桶 
int count;
int L,R,M=0xffff;
int main(){
	int n,m,i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
		scanf("%d",&arr[i]);
	buc[arr[1]]++;
	count++;
	for(l=1,r=1;l<=n;l++){
		buc[arr[l-1]]--;
		//左指针向前进一个,原先最开头的画就不看了,对应画家的桶减1 
		if(buc[arr[l-1]]==0)
		//如果从1减到0了,画家总人数少1 
			count--;
		while(count<m&&r<=n){
			r++;
			//下一次进入while循环的时候,r还保持上一次最后的值,降低了时间复杂度 
			buc[arr[r]]++;
			if(buc[arr[r]]==1)
			//桶内从0增到0,画家总人数多1 
				count++;
		}
		if(count==m&&r-l+1<M){
			//移动左右指针,进入下一轮 
			M=r-l+1;
			//M表示这一轮看了几幅画,如果数量比之前少就更新 
			L=l;R=r;
		}
	}
	printf("%d %d",L,R);
	return 0;
}

P4414 ABC(按指定顺序排列)

【题目描述】
三个整数分别为 A,B,CA,B,C . 这三个数字不会按照这样的顺序给你,但它们始终满足条件: A<B<CA<B<C . 为了看起来更加简洁明了,我们希望你可以按照给定的顺序重新排列它们。
【输入格式】
第一行包含三个正整数 A,B,CA,B,C ,不一定是按这个顺序。这三个数字都小于或等于 100100 。第二行包含三个大写字母 AA 、 BB 和 CC (它们之间没有空格)表示所需的顺序.
【输出格式】
在一行中输出 AA ,BB 和 CC ,用一个 (空格)隔开.

#include <stdio.h>
int BubbleSort(int a[],int n)
{
	int i,j,t;
	for(i=1;i<n;i++)
		for(j=0;j<n-i;j++)
			if(a[j]>a[j+1]){
				t=a[j];
				a[j]=a[j+1];
				a[j+1]=t;
			}
	return 0;
} 
int main(){
	int arr[1024]={0};
	char mark;
	int i=0,j=0;
	for(i=0;i<3;i++){
		scanf("%d",&arr[i]);
	}
	BubbleSort(arr,3);
	getchar();
	//去回车 
	for(j=0;j<4;j++){
	//在dev中j<3即可得到正确结果
		mark=getchar();
		switch(mark){
			case 'A':printf("%d ",arr[0]);break;
			case 'B':printf("%d ",arr[1]);break;
			case 'C':printf("%d ",arr[2]);break;
		}
	}
	return 0;
}
  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值