PAT 甲级 1104 1105 1106 1107 解题报告

今天的四道题相比昨天的四道明显感觉难了好多,作满三小时也没有AK,(实际考试的时候是肯定不会给你三个小时来做题的) 不过好消息是找到了两个思维漏洞,也算是有所收获吧。(程序员的自我安慰ing

1.PAT1104 连续子列和
题目大意:给出一个数列,求出这个数列的所有连续子列的元素之和。
思路:这个题属于典型的会者不难,难者不会类型的题目。找出规律 i*(N-i+1)来就非常简单,13行代码就可以搞定(我当时写得复杂了)。假如没有看出什么规律 即使用DP也会超时,所以遇到类似的问题(PAT1049数1的个数,数量级也是很大)先找找有没有规律,没有找到的话,再想其他的,好在都是暴力可以解的,至少能得一部分分。
注意点:一刷的时候没有发现的一个问题,二刷终于暴露出来了,一刷的时候写的是sum+=num[i]*(i)*(N+1-i); 而二刷的时候一开始写的是sum+=(i)*(N+1-i)&num[i]; 当时虽然也考虑过数组越界问题,但是脑子一短路想成把int的上界当成2 *10^10了后来才意识到上界是 2 *10^9 。(话说现在真想抽自己两下) 所以后面一种写法正好回导致整形的越界,这点一定要注意!!
代码:

#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
const int maxn=100010;
int N;
double num[maxn];
int main(){
	cin>>N;
	for(int i=1;i<=N;i++){
		scanf("%lf",&num[i]);
	}
	double sum=0;
	for(int i=1;i<=N;i++){
		sum+=num[i]*(i)*(N+1-i);
	}
	printf("%.2lf",sum);
}
  1. PAT1105 螺旋序列
    题目大意:给出一个N长度大小的数组,填充成一个螺旋序列
    思路:纯模拟的题,中间有一个大小符号写反了,找了半小时bug。。还是要训练自己找bug的能力啊啊啊,现在想来还是每次填充完就直接输出比较合适。
    代码:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
const int maxn=10010;
int N;
int A,B;
vector<int> v[maxn];
void getAB(int N){
	for(int i=1;i*i<=N;i++){
		if(N%i==0) B=i;
	}
	A=N/B;
}

bool cmp(int a,int b){
	return a>b;
}

int num[maxn];
int main(){
	scanf("%d",&N);
	getAB(N);

	//cout<<A<<B<<endl;
	for(int i=1;i<=A;i++){
		v[i].resize(B+1);
	}
	for(int i=0;i<N;i++){
		scanf("%d",&num[i]);
	}
	sort(num,num+N,cmp);
	int index=0;
	int ed=0;
	while(1){
	for(int i=1+ed;i<=B-ed;i++){
		v[1+ed][i]=num[index++];if(index==N) break;
	}
	//cout<<index<<endl;
	//cout<<1+ed<<" "<<B-ed<<endl;
	if(index==N) break;
	for(int i=2+ed;i<A-ed;i++){
		v[i][B-ed]=num[index++];if(index==N) break;
	}
	//cout<<index<<endl;
	//cout<<2+ed<<" "<<A-ed<<endl;
	if(index==N) break;
	for(int i=B-ed;i>=ed+1;i--){
		v[A-ed][i]=num[index++];if(index==N) break;
	}
	//cout<<index<<endl;
	//cout<<B-ed<<" "<<ed+1<<endl;
	if(index==N) break;
	for(int i=A-1-ed;i>=ed+2;i--){
		v[i][1+ed]=num[index++];if(index==N) break;
	}
	//cout<<index<<endl;
	//cout<<A-1-ed<<" "<<ed+1<<endl;
	if(index==N) break;
	ed++;
	}
	for(int i=1;i<=A;i++){
		for(int j=1;j<=B;j++){
			cout<<v[i][j];
			if(j!=B) cout<<" ";
		}
		cout<<endl;
	}
	return 0;
}
  1. PAT1106 供应商最小价格
    题目大意:给出一个树,求出所有的叶节点最小的层数和最小层数的叶节点数量
    思路:建树再遍历每个节点赋予层值。 有一点二重循环的时候两个循环节都写成了i 。不过幸好这个bug比较好找。
    代码:
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=100010;
int N;
double p,r;
struct Node{
	int layer;
	vector<int> child;
}node[maxn];
void get(int root,int layer){
	node[root].layer=layer;
	for(int i=0;i<node[root].child.size();i++){
		get(node[root].child[i],layer+1);
	}
}

int main(){
	scanf("%d %lf %lf",&N,&p,&r);
	for(int i=0;i<N;i++){
		int temp;scanf("%d",&temp);
		for(int j=0;j<temp;j++){
			int num;scanf("%d",&num);
			node[i].child.push_back(num);
		}
	}
	get(0,0);
	//for(int i=0;i<N;i++) cout<<node[i].layer<<" ";cout<<endl;
	int maxlay=0x3ffffff,ans=0;
	for(int i=0;i<N;i++){
		if(node[i].child.size()==0){
			if(node[i].layer<maxlay) {maxlay=node[i].layer;ans=1;}
			else if(node[i].layer==maxlay) ans++;
		}
	}
	//cout<<maxlay<<endl;
	printf("%.4lf %d",pow(double(1+0.01*r),double(maxlay))*p,ans);
}
	 
  1. PAT1107 兴趣聚类
    题目大意:给出N个人的兴趣,依据兴趣进行聚类,输出同类的个数和同类各个人的数量。
    思路: 并查集,可以不进行路径压缩。同时要注意的是这里是根据兴趣进行合并运算,但是统计的是人的数量。因此需要把兴趣看成这个人的某种属性,合并运算后,再进行一次遍历,按照不同的集合,把人进行归类。最后输出。
    注意点:由于好久没写并查集了,重新写代码的过程中犯了一个典型的错误。
void Union(int a,int b){
	int A=getfa(a);
	int B=getfa(b);
	if(A!=B) father[B]=A;
}

注意合并集合都是根据父节点进行操作的,所以这里应该把父节点之间进行合并,而不是father[b] = a ,这点十分关键。 原因如图
代码:

#include <algorithm>
#include <vector>
#include <iostream>
#include <unordered_map>
using namespace std;
const int maxn=10010;
int father[maxn],N;
vector<int> stu[maxn];
unordered_map<int,int> m;
void re(){
	for(int i=0;i<maxn;i++) father[i]=i;
}

int getfa(int x){
	int a=x;
	while(x!=father[x]){x=father[x];}
	while(a!=x){
		int s=father[a];
		father[a]=x;
		a=s;
	}
	return x;
}

bool cmp(int a,int b){return a>b;}

void Union(int a,int b){
	int A=getfa(a);
	int B=getfa(b);
	if(A!=B) father[B]=A;
}

int main(){
	re();
	int N;scanf("%d",&N);
	for(int i=0;i<N;i++){
		int size,fa;scanf("%d: %d",&size,&fa);
		stu[i].push_back(fa);
		for(int j=1;j<size;j++){
			int temp;scanf("%d",&temp);
            stu[i].push_back(temp);
			Union(fa,temp);
		}
	}
	for(int i=0;i<N;i++){
		int x=getfa(stu[i][0]);
		if(m.find(x)==m.end()){
			m[x]=1;
		}
		else m[x]++;
	}
	cout<<m.size()<<endl;
	vector<int> ans; 
	for(auto it=m.begin();it!=m.end();it++){
		ans.push_back(it->second);
	}
	sort(ans.begin(),ans.end(),cmp);
	for(int i=0;i<ans.size();i++){
		printf("%d",ans[i]);if(i!=ans.size()-1)cout<<" ";
	}
}

总之还是任重而道远,与bug的竞争还有很长的一段路要走。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值