第二次上机考试题解

T1:数列查询

在这里插入图片描述

这道题最多查询10000次,若单纯使用递归,会有多次重复计算的过程,所以可以用一个数组存放递归过程中计算得到的结果。在查询f(i)时,如果f(i)之前已经计算过了,直接输出即可;若没计算过,则进行计算并存放到数组中。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[1000000+9];
int F(int x){
	if(f[x])return f[x];
	else if(x==1)return f[1]=10;
	else return f[x]=F(x-1)*11/10; 
}
int q;
int main(){
	scanf("%d",&q);
	int x;
	for(int i=0;i<q;i++){
		scanf("%d",&x);
		printf("%d\n",F(x));
	}
	return 0;
}

T2:稀疏矩阵之差

在这里插入图片描述

这道题是用三元组表示的,输入矩阵时是按行列排序输入的,所以直接存放即可,不用再进行排序。若A,B的行列数不同,则直接输出"Illegal!"。计算A-B时,从头开始进行操作,分别用pa,pb指向A,B当前要进行操作的元素,如果A[pa],B[pb]行列相同,则比较二者的值,若相减为0,则不存放到C中,若不为0,则存放到C中,cnt++(cnt记录矩阵C中非0数据项的个数)。若A[pa],B[pb]行列不相同,则按照先行后列的顺序,对优先级高的进行操作,存放到C中,cnt++,同时,这个矩阵(指刚刚优先级高的数据所在的矩阵)的指针(pa/pb)移动到下一位,另一个没有进行操作的矩阵,指针不变。

代码如下:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
int N1,M1,t1,N2,M2,t2;
int cnt;

struct node{
	int x,y;
	int data;
};

node a[50000+5],b[50000+5],c[500000+5];

void work(){
	if(!((N1==N2)&&(M1==M2))){
		printf("Illegal!");
		exit(0);
	}else{
		int pa=0,pb=0,j;
		for(j=0;pa<t1&&pb<t2;){
			if(a[pa].x==b[pb].x&&a[pa].y==b[pb].y){  //行列相同时
				if(a[pa].data==b[pb].data);    //相减为0,不存放
				else{
					c[j].x=a[pa].x;
					c[j].y=a[pa].y;
					c[j].data=a[pa].data-b[pb].data;
					j++;		
				}
				pa++;pb++;
			}else if(a[pa].x==b[pb].x){
				if(a[pa].y<b[pb].y){
					c[j].x=a[pa].x;
					c[j].y=a[pa].y;
					c[j].data=a[pa].data;
					pa++;
				}else{
					c[j].x=b[pb].x;
					c[j].y=b[pb].y;
					c[j].data=-b[pb].data;
					pb++;
				}
				j++;
			}else if(a[pa].x<b[pb].x){
				c[j].x=a[pa].x;
				c[j].y=a[pa].y;
				c[j].data=a[pa].data;
				pa++;
				j++;
			}else{
				c[j].x=b[pb].x;
				c[j].y=b[pb].y;
				c[j].data=-b[pb].data;
				pb++;
				j++;
			}
		}
		cnt=j;
		if(pa>=t1&&pb>=t2)return;
		else if(pa>=t1){
			for(;pb<t2;j++,pb++){
				c[j].x=b[pb].x;
				c[j].y=b[pb].y;
				c[j].data=-b[pb].data;
			}
		}else{
			for(;pa<t1;j++,pa++){
				c[j].x=a[pa].x;
				c[j].y=a[pa].y;
				c[j].data=a[pa].data;
			}
		}
		cnt=j;
	}
}

void print(){
	printf("%d %d %d\n",N1,M1,cnt);
	for(int i=0;i<cnt;i++){
		printf("%d %d %d\n",c[i].x,c[i].y,c[i].data);
	}
}


int main(){
	scanf("%d%d%d",&N1,&M1,&t1);
	int x,y;
	long long data;
	for(int i=0;i<t1;i++){
		scanf("%d%d%d",&x,&y,&data);
		a[i].x=x;
		a[i].y=y;
		a[i].data=data;
	}
	scanf("%d%d%d",&N2,&M2,&t2);
	for(int i=0;i<t2;i++){
		scanf("%d%d%d",&x,&y,&data);
		b[i].x=x;
		b[i].y=y;
		b[i].data=data;
	}
	work();
	print();
	return 0;
}

T3:文字编辑

在这里插入图片描述

这道题是跳舞链的应用。

代码如下:

#include<iostream>
#include<cstdio>

using namespace std;

int t;      //有t组测试数据
int n,m;
int Left[10000+8],Right[10000+8];

// Left[i]表示编号为 i 的汉字的前一个汉字的编号 
/// Right[i] 表示编号为 i 的汉字的后一个汉字的编号 



int main(){
	scanf("%d",&t);
	char s;
	int x,y;
	for(int i=0;i<t;i++){
		scanf("%d%d",&n,&m);
		for(int j=1;j<=n;j++){    //初始化
			Left[j]=j-1;
			Right[j]=j+1;
		}
		Left[1]=n;
		Right[n]=1;
		for(int j=0;j<m;j++){
			scanf("\n%c%d%d",&s,&x,&y);
/* 读入时前面加回车,否则会将上一个操作的回车当作操作数读进来。或者直接用字符串读也可以,因为使用 %s 读入字符串的时候会自动忽略回车、空格等空白字符。*/
			if(s=='A'){
				Right[Left[x]]=Right[x];     //跳舞脱离原链
				Left[Right[x]]=Left[x];
				Right[Left[y]]=x;
				Left[x]=Left[y]; 
				Left[y]=x;
				Right[x]=y;
			}else if(s=='B'){
				Right[Left[x]]=Right[x];     //跳舞脱离原链
				Left[Right[x]]=Left[x];
				Left[Right[y]]=x;
				Right[x]=Right[y];
				Right[y]=x;
				Left[x]=y;
			}else{
				if(x==0){
					printf("%d\n",Left[y]);
				}else{
					printf("%d\n",Right[y]);
				}
			}
		}
	}
	return 0;
}

T4:幸福指数

在这里插入图片描述

用Day数组存放每天的幸福值,Pre存放幸福值的前缀和。对每一个元素Day[i],找以Day[i]为最小值的区间,即找Day[i]左边和右边第一个比其小的元素。因此我们可以用单调栈来维护,然后用数组L[i],R[i]分别存放左边右边第一个比其小的元素的下标,最后再进行比较。但要注意题目要求最长最左区间,所以要单独判断一下。(要用long long)

代码如下:

#include<iostream>
#include<cstdio>
#include<stack>
#define MAX 10000000

using namespace std;
int n;
long long ans;
int FL,FR;
int L[MAX],R[MAX];
long long Day[MAX],Pre[MAX];
stack<int> s;   //s存放下标 


int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&Day[i]);
		Pre[i]=Pre[i-1]+Day[i];
	}
	Day[0]=-100;Day[n+1]=-100;
	s.push(0);
	for(int i=1;i<=n;i++){
		while(Day[s.top()]>=Day[i]) s.pop();
		L[i]=s.top();
		s.push(i);
	}
	while(!s.empty())s.pop();
	s.push(n+1);
	for(int i=n;i>=1;i--){
		while(Day[s.top()]>=Day[i])s.pop();
		R[i]=s.top();
		s.push(i);
	}
	ans=Day[1];
	FL=FR=1;
	for(int i=1;i<=n;i++){
		long long tmp=(Pre[R[i]-1]-Pre[L[i]])*Day[i];
		if(ans<tmp){
			ans=tmp;
			FL=L[i]+1;
			FR=R[i]-1;
		}else if(ans==tmp){
			int dl=L[i]+1;
			int dr=R[i]-1;
			if(FR-FL<dr-dl){   //判断最长
				FR=dr;
				FL=dl;
			}else if(dr-dl==FR-FL){  //判断最左
				if(dl<FL){
					FL=dl;
					FR=dr;
				}
			}
		}
	}
	printf("%lld\n%d %d",ans,FL,FR);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值