PAT | 模拟题:A1046/A1065/B1010/A1002/A1009

这篇博客主要解析了PAT(Advanced Level)中的一些算法题目,包括A1046 Shortest Distance的问题优化,通过改变表示方式实现O(1)时间复杂度求解;A1065 A+B and C (64bit)中涉及的溢出问题,分析了不同溢出情况的判断;B1010多项式求导的输入输出处理;A1002 A+B for Polynomials的错误分析,提出用数组记录系数的解决思路;以及A1009 Product of Polynomials,注意结果数组大小的设定。
摘要由CSDN通过智能技术生成

A1046

【Notes】超时

题目地址

PAT (Advanced Level) Practice #1046 Shortest Distance

问题代码

【Notes】其实已经做过一次修改,将向另一个方向的距离改为用sum-d1来表示。

#include<cstdio>
const int maxn=100005;
int d[maxn]={0};

int main()
{
	int n,m,sum=0;scanf("%d",&n);
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&d[i]);
		sum+=d[i];
	}
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		int maxx,a,b,temp,d1=0,d2=0;
		scanf("%d%d",&a,&b);
		if(a>b)
		{
			temp=a;
			a=b;
			b=temp;
		}
		for(int j=a;j<b;j++) d1+=d[j];
        d2=sum-d1; 
		
		if(d1>=d2) maxx=d2;
		else maxx=d1;
		printf("%d\n",maxx);
	}
	return 0;
}

修改

dis[i]表示1号结点按顺时针方向到达“第i号结点顺时针方向的下一个结点”的距离。这样二者相减即可得到距离,时间复杂度为 O ( 1 ) O(1) O(1)

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
int d[maxn]={0};
int dis[maxn]={0};    

int main()
{
	int n,m,sum=0;
	int a,b,temp;//定义在for循环内会出错(原因?) 
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
	{
		scanf("%d",&d[i]);
		sum+=d[i];
		dis[i]=sum;
	}
	scanf("%d",&m);
	for(int i=0;i<m;i++)
	{
		//int a,b,temp;
		scanf("%d%d",&a,&b);
		/* 
		if(a>b)
		{
			temp=a;
			a=b;
			b=temp;
		}*/
		if(a>b) swap(a,b); //有可以直接用的swap函数 
		//for(int j=a;j<b;j++) d1+=d[j];
        //d2=sum-d1; 
		//if(d1>=d2) maxx=d2;
		//else maxx=d1;
		temp=dis[b-1]-dis[a-1];
		printf("%d\n",min(temp,sum-temp));
	}
	return 0;	
}

A1065

【Notes】溢出问题

题目地址

PAT (Advanced Level) Practice #1065 A+B and C (64bit)

问题代码

【Notes】想得也太简单了= - =

#include<cstdio>

int main()
{
	long long int a,b,c;
	int n; scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%lld%lld%lld",&a,&b,&c);
		if((a+b)>c) printf("Case #%d: true\n",i+1);
		else  printf("Case #%d: false\n",i+1);
	} 
	return 0;
}

修改

  • long long 的范围是 [ − 2 63 , 2 63 ) [-2^{63},2^{63}) [263,263) 因此题目中的数字相加会导致溢出;
  • 正数之和成负数,负数之和成整数则为溢出;
  • 只需与0比较即可。

【情况分析】

  1. A + B ≥ 2 63 A+B\ge2^{63} A+B263显然 A + B > C A+B>C A+B>C成立;但会发生正溢出,由题目条件, A + B A+B A+B最大为 2 64 − 2 2^{64}-2 2642因此使用long long溢出后值的区间为 [ − 2 63 , − 2 ] [-2^{63},-2] [263,2]
    (由 ( 2 64 − 2 ) % ( 2 64 ) = − 2 (2^{64}-2)\%(2^{64})=-2 (2642)%(264)=2计算得出)。# 涉及计组吗
  2. A + B < − 2 63 A+B<-2^{63} A+B<263显然 A + B < C A+B<C A+B<C成立;但会发生负溢出。同上,负溢出后值的区间为 [ 0 , 2 63 ) [0,2^{63}) [0,263)(由 ( − 2 64 ) % ( 2 64 ) = 0 (-2^{64})\%(2^{64})=0 (264)%(264)=0计算得出)
  3. 无溢出的情况正常比较即可。
#include<cstdio>

int main()
{
	int T, tcase=1;
	scanf("%d",&T);
	while(T--)
	{
		long long a,b,c;
		scanf("%lld%lld%lld",&a,&b,&c);
		long long res = a+b;
		bool flag;
		if(a>0&&b>0&&res<0) flag = true;//判断是否正溢出 
	    else if(a<0&&b<0&&res>=0) flag=false;
	    else if(res>c) flag=true;
	    else flag=false;
	    if(flag==true) printf("Case #%d: true\n",tcase++);
	    else printf("Case #%d: false\n",tcase++);
	}
	return 0;
}

B1010

【Notes】输入问题、输出格式

题目地址

PAT (Basic Level) Practice #1010 多项式求导

问题代码

  • 如何输入
  • 如何防止末尾空格
  • 零多项式什么意思
#include<cstdio>
const int maxn = 1000;

int main()
{
	int a[maxn]={0},b[maxn]={0};
	int m,n;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		if(n) 
		{
			printf("%d %d",m*n,n-1);
		    printf(" "); 
		}
	}
	return 0;
}  

修改

  • 输入:while…EOF的使用
  • 输出:用一个变量来计数即可控制空格
#include<cstdio>

int main()
{
	int m,n,cnt=0;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		if(m&&n) 
		{
			if(cnt!=0) printf(" ");
			printf("%d %d",m*n,n-1);
			cnt++;
		} 
	}
	if(cnt==0) printf("0 0");
	return 0;
} 

A1002

题目地址

PAT (Advanced Level) Practice #1002 A+B for Polynomials

问题代码

【Notes】Wrong Answer

//2.4x+3.2
//1.5x^2+0.5x
//1.5x^2+ 
#include<cstdio>
#include<algorithm>
using namespace std;

struct node
{
	int n;
	float a;
};
node item1[11];
node item2[11];
node item[11];
int main()
{
	int k1,k2,cnt=0;
	scanf("%d",&k1);
	for(int i=0;i<k1;i++) 
	    scanf("%d%f",&item1[i].n,&item1[i].a);
	scanf("%d",&k2);
	for(int i=0;i<k2;i++) 
	    scanf("%d%f",&item2[i].n,&item2[i].a);
	
	int dk=max(k1,k2);
	int sk=min(k1,k2);
	int t=0,i=0,j=0;
	while(1)
	{
        if((j==k2)&&(i!=k1)) 
        {
        	item[t].n=item1[i].n;
			item[t].a=item1[i].a;
			t++;
			i++;
			continue;
		}
		if((i==k1)&&(j!=k2))
        {
        	item[t].n=item2[j].n;
			item[t].a=item2[j].a;
			t++;
			j++;
			continue;
		}
		if((i==k1)&&(j==k2)) break;
		if(item1[i].n<item2[j].n) 
		{
			item[t].n=item2[j].n;
			item[t].a=item2[j].a;
			t++; 
			j++;
		}
		else if(item1[i].n==item2[j].n)
		{
			item[t].n=item1[i].n;
			item[t].a=item1[i].a+item2[j].a;
			t++; i++;j++;
		}
		else if(item1[i].n>item2[j].n)
		{
			item[t].n=item1[i].n;
			item[t].a=item1[i].a;
			t++;
			i++;
		}
	}	
	printf("%d ",t);
	for(int k=0;k<t;k++) 
	{
		printf("%d %.1f",item[k].n,item[k].a);
		if(k!=t-1) printf(" ");
	}
}

【问题】 待查找。。

修改

思路:用数组a[i]记录指数为i的项的系数即可。

#include<cstdio>
const int maxn=1005;
double a[maxn]={0.0};
double b[maxn]={0.0};
double c[maxn]={0.0};

int main()
{
    int n1,n2,e,cnt=0;
    double k;
	scanf("%d",&n1);
	for(int i=0;i<n1;i++)
	{
		scanf("%d%lf",&e,&k);
		a[e]=k;
	}
	scanf("%d",&n2);
	for(int i=0;i<n2;i++)
	{
		scanf("%d%lf",&e,&k);
		b[e]=k;
	}	
	for(int i=0;i<1001;i++)
	{
		c[i]=a[i]+b[i];
		if(c[i]!=0) cnt++;
	}
	printf("%d",cnt);
	
	for(int i=1000;i>=0;i--)
	{
		if(c[i]!=0)
		{
			if(cnt) printf(" ");
			printf("%d %.1f",i,c[i]);
		    cnt--;
		}
	}
	return 0;
} 

A1009

【Notes】与上题思路相同,但要注意开的数组的大小。因为两个输入的最高次项为1000,所以结果数组开的大小应该至少为2001。

题目地址

PAT (Advanced Level) Practice #1009 Product of Polynomials

代码

#include<cstdio>
const int maxn=2001;
double a[maxn]={0.0};
double b[maxn]={0.0};
double c[maxn]={0.0};

int main()
{
    int n1,n2,e,cnt=0;
    double k;
	scanf("%d",&n1);
	for(int i=0;i<n1;i++)
	{
		scanf("%d%lf",&e,&k);
		a[e]=k;
	}
	scanf("%d",&n2);
	for(int i=0;i<n2;i++)
	{
		scanf("%d%lf",&e,&k);
		b[e]=k;
	}	
	for(int i=0;i<1001;i++)
	{
		for(int j=0;j<1001;j++)
		{
			c[i+j]+=a[i]*b[j];
		}
	}
	
	for(int i=0;i<2001;i++) if(c[i]!=0) cnt++;
	printf("%d",cnt);
	
	for(int i=2000;i>=0;i--)
	{
		if(c[i]!=0)
		{
			if(cnt) printf(" ");
			printf("%d %.1f",i,c[i]);
		    cnt--;
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值