【PAT】第四章 算法初步(例题)

第四章 算法初步

4.1 排序

【例】A1062 Talent and Virtue (25 分)

ATTENTION

  • 水题,但是你的笔误真的有点多。要多注意下笔。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

struct per{
	int id;
	int vgrade,tgrade;
	per(){}
	per(int i,int v,int t){id=i;vgrade=v;tgrade=t;}
}; 
vector<per> sage,noble,fool,remain;
int n,l,h;

bool cmp(per &a,per &b)
{
	if((a.tgrade+a.vgrade)==(b.vgrade+b.tgrade))
	{
		if(a.vgrade==b.vgrade)
			return a.id<b.id;
		return a.vgrade>b.vgrade;
	}
	return (a.tgrade+a.vgrade)>(b.vgrade+b.tgrade);
}
int main()
{
	scanf("%d %d %d",&n,&l,&h);
	for(int i=0;i<n;i++)
	{
		int id,v,t;
		scanf("%d %d %d",&id,&v,&t);
		per tmp(id,v,t);
		if(v>=h&&t>=h) sage.push_back(tmp);
		else if(v>=h&&t<h&&t>=l) noble.push_back(tmp);
		else if(t>=l&&v>=t&&v>=l) fool.push_back(tmp);
		else if(t>=l&&v>=l) remain.push_back(tmp);
	}
	sort(sage.begin(),sage.end(),cmp);
	sort(noble.begin(),noble.end(),cmp);
	sort(fool.begin(),fool.end(),cmp);
	sort(remain.begin(),remain.end(),cmp);
	printf("%d\n",sage.size()+noble.size()+fool.size()+remain.size());
	for(int i=0;i<sage.size();i++)
		printf("%d %d %d\n",sage[i].id,sage[i].vgrade,sage[i].tgrade);
	for(int i=0;i<noble.size();i++)
		printf("%d %d %d\n",noble[i].id,noble[i].vgrade,noble[i].tgrade);
	for(int i=0;i<fool.size();i++)
		printf("%d %d %d\n",fool[i].id,fool[i].vgrade,fool[i].tgrade);
	for(int i=0;i<remain.size();i++)
		printf("%d %d %d\n",remain[i].id,remain[i].vgrade,remain[i].tgrade);
	return 0;
}
	

【例】A1012 The Best Rank (25 分)

ATTENTION

  • 按理说也是道水题,但是debug了很久,很多小错误。
  • 对于这种对限定范围排序的题目,尤其不是从0开始的,要注意每个for循环的界限。这道题就是因为四个sort以及对应的for循环,和最后一个输出的for循环的界限有问题,才有很多wa
  • 排序:貌似PAT例默认的是,同分同名次,但排名根据人数走,比如:99 98 98 97,那么排名为1 2 2 4。
  • 对于**ididx的映射**,由于这道题的范围比较小,可以开数组形成映射。代码里是通过map实现映射的。
  • 考场上要细心一点!
#include <string>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;

int n,m;
struct per{
	int id;
	int cg,mg,eg,ag;
	int bestRank;
	char bestLan;
	per() { cg=mg=eg=ag=bestRank=1e9; }
	per(int i,int c,int m,int e,int a)
	{
		id=i;cg=c;mg=m;eg=e;ag=a;
		bestRank=1e9;
	}
};
vector<per> stu;
map<int,int> nameToIdx;

bool cmp1(per &a,per &b){return a.ag>b.ag;}
bool cmp2(per &a,per &b){return a.cg>b.cg;}
bool cmp3(per &a,per &b){return a.mg>b.mg;}
bool cmp4(per &a,per &b){return a.eg>b.eg;}
int main()
{
	scanf("%d %d",&n,&m);
	per tmp(0,0,0,0,0); 	//0不用 
	stu.push_back(tmp);
	for(int i=1;i<=n;i++)
	{
		int id,c,m,e;
		scanf("%d %d %d %d",&id,&c,&m,&e);
		int a=(c+m+e)/3;
		nameToIdx[id]=i;
		per tmp(id,c,m,e,a);
		stu.push_back(tmp);
	}
	sort(stu.begin()+1,stu.end(),cmp1);
	int pre=0,idx=0;
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			idx=i;
			pre=1;
		}
		else
		{
			if(stu[i].ag==stu[i-1].ag)
				idx=pre;
			else
				idx=i;
		}
		pre=idx;
		if(stu[i].bestRank>idx)
		{
			stu[i].bestRank=idx;
			stu[i].bestLan='A';
		}
	}
	sort(stu.begin()+1,stu.end(),cmp2);
	pre=0;idx=0;
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			idx=i;
			pre=1;
		}
		else
		{
			if(stu[i].cg==stu[i-1].cg)
				idx=pre;
			else
				idx=i;
		}
		pre=idx;
		if(stu[i].bestRank>idx)
		{
			stu[i].bestRank=idx;
			stu[i].bestLan='C';
		}
	}
	sort(stu.begin()+1,stu.end(),cmp3);
	pre=0;idx=0;
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			idx=i;
			pre=1;
		}
		else
		{
			if(stu[i].mg==stu[i-1].mg)
				idx=pre;
			else
				idx=i;
		}
		pre=idx;
		if(stu[i].bestRank>idx)
		{
			stu[i].bestRank=idx;
			stu[i].bestLan='M';
		}
	}
	sort(stu.begin()+1,stu.end(),cmp4);
	pre=0;idx=0;
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			idx=i;
			pre=1;
		}
		else
		{
			if(stu[i].eg==stu[i-1].eg)
				idx=pre;
			else
				idx=i;
		}
		pre=idx;
		if(stu[i].bestRank>idx)
		{
			stu[i].bestRank=idx;
			stu[i].bestLan='E';
		}
	}	
	for(int i=0;i<m;i++)
	{
		int id;
		scanf("%d",&id);
		vector<per>::iterator it;
		for(it=stu.begin()+1;it!=stu.end();it++)
		{
			if(it->id==id)
				break;
		}
		if(it!=stu.end())
			printf("%d %c\n",it->bestRank,it->bestLan);
		else
			printf("N/A\n");
	}
	return 0;
}

【例】A1025 PAT Ranking (25 分)

simultaneously adv. 同时地
merge vi. 合并;融合

ATTENTION

  • 水题。输入的同时得到每个考场的rank。最后再sort所有stu,得到TOTRank
//simultaneously merge
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int n,k,cnt=0;
struct per{
	string id;
	int score,localIdx,localRank,totRank;
	per(){}
	per(string d,int li,int s){id=d;localIdx=li;score=s;}
};
vector<per> stu;

bool cmp(per &a,per &b)
{
	if(a.score==b.score)
		return a.id<b.id;
	return a.score>b.score;
}

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>k;
		for(int j=1;j<=k;j++)
		{
			string id;int s;
			cin>>id>>s;
			per tmp(id,i,s);
			stu.push_back(tmp);
		}
		sort(stu.begin()+cnt,stu.begin()+cnt+k,cmp);
		int pre=1;
		for(int j=cnt;j<cnt+k;j++)
		{
			if(j==cnt)	stu[j].localRank=1;
			else
			{
				if(stu[j].score!=stu[j-1].score)
					stu[j].localRank=j-cnt+1;
				else
					stu[j].localRank=pre;
			}
			pre=stu[j].localRank;
		}
		cnt+=k;
	}
	sort(stu.begin(),stu.end(),cmp);
	int pre=1;
	for(int i=0;i<stu.size();i++)
	{
		if(i==1)	stu[i].totRank=pre;
		else
		{
			if(stu[i].score==stu[i-1].score)
				stu[i].totRank=pre;
			else
				stu[i].totRank=i+1;
		}
		pre=stu[i].totRank;
	}
	cout<<cnt<<"\n";
	for(int i=0;i<stu.size();i++)
		cout<<stu[i].id<<" "<<stu[i].totRank<<" "<<stu[i].localIdx<<" "<<stu[i].localRank<<"\n";
	return 0;
}

【例】A1028 List Sorting (25 分)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int n,c;
struct per{
	int grade;
	string id,name;
	per(string n,string d,int g) { name=n;id=d;grade=g; }
};
vector<per> stu;

bool cmp1(per &a,per &b)
{
	return a.id<b.id;
}
bool cmp2(per &a,per &b)
{
	if(a.name==b.name)
		return a.id<b.id;
	return a.name<b.name; 
}
bool cmp3(per &a,per &b)
{
	if(a.grade==b.grade)
		return a.id<b.id;
	return a.grade<b.grade;
}
int main()
{
	cin>>n>>c;
	for(int i=0;i<n;i++)
	{
		string n,d;int s;
		cin>>d>>n>>s;
		per tmp(n,d,s);
		stu.push_back(tmp);
	}
	if(c==1)
	{
		sort(stu.begin(),stu.end(),cmp1);
		for(int i=0;i<stu.size();i++)
			cout<<stu[i].id<<" "<<stu[i].name<<" "<<stu[i].grade<<"\n";
	}
	else if(c==2)
	{
		sort(stu.begin(),stu.end(),cmp2);
		for(int i=0;i<stu.size();i++)
			cout<<stu[i].id<<" "<<stu[i].name<<" "<<stu[i].grade<<"\n";
	}
	else if(c==3)
	{
		sort(stu.begin(),stu.end(),cmp3);
		for(int i=0;i<stu.size();i++)
			cout<<stu[i].id<<" "<<stu[i].name<<" "<<stu[i].grade<<"\n";
	}
	return 0;
}


【例】A1055 The World’s Richest (25 分)

ATTENTION

  • 这道题可以做预处理,即只存储某个年龄的前100位最优财富的人
  • PAT卡时间卡的很死。有时候,只有最佳方法才能ac。在考试的时候,对于这些点,要在数据量极大的情况下去考虑,否则,比如这道题,在数据量小的时候去考虑只存储前100个就很难想到。
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int n,k,m;
struct per{
	string name;
	int age,worth;
	per(){}
	per(string n,int a,int w){name=n;age=a;worth=w;}
};
vector<per> big;

bool cmp(per &a,per &b)
{
	if(a.worth==b.worth)
	{
		if(a.age==b.age)
			return a.name<b.name;
		return a.age<b.age;
	}
	return a.worth>b.worth;
}
int main()
{
	scanf("%d %d",&n,&k);
	string name;
	int age,worth;
	for(int i=0;i<n;i++)
	{
		cin>>name;
		scanf("%d %d",&age,&worth);
		per tmp(name,age,worth);
		big.push_back(tmp);
	}
	
	sort(big.begin(),big.end(),cmp);
	int mmin,mmax;
	for(int i=1;i<=k;i++)
	{
		int cnt=0;
		scanf("%d %d %d",&m,&mmin,&mmax);
		printf("Case #%d:\n",i);
		for(int j=0;j<big.size();j++)
		{
			if(cnt==m) break;
			if(big[j].age>=mmin&&big[j].age<=mmax)
			{
				printf("%s %d %d\n",big[j].name.c_str(),big[j].age,big[j].worth);
				cnt++;
			}
		}
		if(cnt==0)
			printf("None\n");	
	}
}

【例】A1083 List Grades (25 分)

with respect to 关于

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
//with respect to 关于 
struct PER{
	string name,id;
	int grade;
	
	PER(string n,string i,int g)
	{
		name=n;
		id=i;
		grade=g;
	}
};
vector<PER> stu;

int n,g1,g2;


bool cmp(PER a,PER b)
{
	return a.grade>b.grade;
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		string s1,s2;int g;
		cin>>s1>>s2>>g;
		PER tmp(s1,s2,g);
		stu.push_back(tmp);
	}
	cin>>g1>>g2;
	bool flag=false;
	sort(stu.begin(),stu.end(),cmp); 	//
	for(int i=0;i<stu.size();i++)
	{
		if(stu[i].grade<=g2&&stu[i].grade>=g1)
		{
			flag=true;
			cout<<stu[i].name<<" "<<stu[i].id<<endl;
		}
			
	}
	if(!flag)
		cout<<"NONE";
	return 0;	
}

*【例】A1089 Insert or Merge (25 分)

//adjacent resule
//插入排序和归并排序其实都可以用sort实现 
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

int n;
int ins[110],mer[110],ans[110]; 

void insertSort(int i)
{
	int idx=i,tmp=ins[i];
	for(int j=1;j<i;j++)
	{
		if(ins[i]<ins[j])
		{
			idx=j;
			break;
		}
	}
	for(int j=i-1;j>=idx;j--)
		ins[j+1]=ins[j];
	ins[idx]=tmp;
}
bool isEqual(int cur[],int n)
{
	for(int i=1;i<=n;i++)
		if(cur[i]!=ans[i]) return false;
	return true;
}
void mergeSort(int t)
{
	int len=t;
	for(int i=1;i<=n;i+=len)
	{
		int end=min(i+len,1+n);
		sort(mer+i,mer+end);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&ins[i]);
		mer[i]=ins[i];
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&ans[i]);
	
	for(int i=2;i<=n;i++)
	{
		insertSort(i);
		if(isEqual(ins,n))
		{
			printf("Insertion Sort\n");
			insertSort(i+1);
			for(int j=1;j<=n;j++)
			{
				if(j==1) printf("%d",ins[j]);
				else printf(" %d",ins[j]);
			}
		}
	}
	int cnt=2;
	while(cnt<=n)
	{
		mergeSort(cnt);
		cnt*=2;
		if(isEqual(mer,n))
		{
			printf("Merge Sort\n");
			mergeSort(cnt);
			for(int j=1;j<=n;j++)
			{
				if(j==1) printf("%d",mer[j]);
				else printf(" %d",mer[j]);
			}
		}
	}
	return 0;
}

4.2 散列

【例】A1084 Broken Keyboard (20 分)

detect vt. 察觉;发现;探测
captilize 首字母大写其余字母小写

ATTENTION

  • 像这种数据量很小的题,直接用数组映射即可。
  • 先枚举第二个字符串,将出现过的字符设为1。再枚举第一个字符串,没出现过的字符就是无法输出的字符。为了不重复输出,在检测到一个不能输出的字符后,将其也设为1。
#include <iostream>
#include <string>
#include <vector> 
using namespace std;

string s1,s2;
bool vis[100]={0}; 	//0-9 A-Z _
vector<char> ans;

int main()
{
	cin>>s1>>s2;
	for(int i=0;i<s2.size();i++)
	{
		if(s2[i]>='a'&&s2[i]<='z')
			s2[i]=s2[i]-'a'+'A';
		if(s2[i]>='0'&&s2[i]<='9')
			vis[s2[i]-'0']=1;
		else if(s2[i]>='A'&&s2[i]<='Z')
			vis[s2[i]-'A'+20]=1;
		else
			vis[50]=1;
	}
	for(int i=0;i<s1.size();i++)
	{
		int idx=0;
		if(s1[i]>='a'&&s1[i]<='z')
			s1[i]=s1[i]-'a'+'A';
		if(s1[i]>='0'&&s1[i]<='9')
			idx=s1[i]-'0';
		else if(s1[i]>='A'&&s1[i]<='Z')
			idx=s1[i]-'A'+20;
		else
			idx=50;
		if(vis[idx]==0)
		{
			cout<<s1[i];
			vis[idx]=1;
		}
	}
	return 0;
}

【例】A1092 To Buy or Not to Buy (20 分)

bead n.珠子
string n. 线,弦,细绳;一串,一行

ATTENTION

  • 先分别记录两个字符串出现过的字符以及出现的次数。
  • 然后对于每一种珠子进行枚举,如果e[i]>s[i],则说明结果为No,且两数之差为miss的数量;反之,结果为Yes,且两数之差为要多买的数量。
#include <iostream>
#include <string>
using namespace std;

int e[100]={0};  //0~9 -'0' ; a~z -'a'+20 ; A~Z -'A'+50
int s[100]={0};

string shop,eva;

int main()
{
	cin>>shop>>eva;
	for(int i=0;i<shop.size();i++)
	{
		if(shop[i]>='0'&&shop[i]<='9')
			s[shop[i]-'0']++;
		else if(shop[i]>='a'&&shop[i]<='z')
			s[shop[i]-'a'+20]++;
		else
			s[shop[i]-'A'+50]++;
	}
	for(int i=0;i<eva.size();i++)
	{
		if(eva[i]>='0'&&eva[i]<='9')
			e[eva[i]-'0']++;
		else if(eva[i]>='a'&&eva[i]<='z')
			e[eva[i]-'a'+20]++;
		else
			e[eva[i]-'A'+50]++;
	}
	int ans=0,miss=0;
	bool flag=true;
	for(int i=0;i<100;i++)
	{
		if(s[i]>=e[i])
			ans+=s[i]-e[i];
		else
		{
			miss+=e[i]-s[i];
			flag=false;
		}	
	}
	if(flag)
		cout<<"Yes"<<" "<<ans;
	else
		cout<<"No"<<" "<<miss;
}


【例】A1041 Be Unique (20 分)

lottery n. 彩票;碰运气的事,难算计的事;抽彩给奖法

ATTENTION

  • vis数组中记录下标数出现的次数。在num数组中记录下标数第一次出现的序号。
  • 遍历vis数组,对于仅出现过一次的数,查找num数组,寻找最早出现的那个。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int n;
int num[20000];
int vis[20000]={0};

int main()
{
	scanf("%d",&n);
	fill(num,num+20000,-1);
	fill(vis,vis+20000,0);
	for(int i=0;i<n;i++)
	{
		int tmp;
		scanf("%d",&tmp);
		if(vis[tmp]==0)
			num[tmp]=i;
		vis[tmp]++;
	}
	int idx=200000,ans=-1;
	for(int i=1;i<10001;i++)
	{
		if(vis[i]==1&&num[i]<idx)
		{
			idx=num[i];
			ans=i;
		}
	}
	if(ans==-1)
		printf("None");
	else
		printf("%d",ans);
}

【例】A1050 String Subtraction (20 分)

Subtraction n. [数] 减法;减少;差集

#include <iostream>
#include <string>
using namespace std;

int letter[300]={0};

string s1,s2,s;

int main()
{
	//cin不能读入空格 
	getline(cin,s1);
	getline(cin,s2);
	for(int i=0;i<s2.size();i++)
	{
		int tmp=(int)s2[i];
		letter[tmp]=-1;
	}
	for(int i=0;i<s1.size();i++)
	{
		int tmp=(int)s1[i];
		if(letter[tmp]==0)
			cout<<s1[i];
	}
}

【例】A1048 Find Coins (25 分)

ATTENTION

  • 一般大部分点都过了但少部分点没过的时候,就是有情况没有被考虑到,比如这道题,如果i==m-i是答案,那么就要确保至少有两个i
  • 这道题也可以用two pointers做,先把所有的数从小到大排序(不能删去重复的),然后同时从左和从右开始寻找。
#include <iostream>
using namespace std;

int n,m;
int vis[1010]={0};

int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)
	{
		int tmp;
		cin>>tmp;
		vis[tmp]++;
	}
	bool flag=false;
	for(int i=1;i<m;i++)
	{
		if(vis[i]!=0&&vis[m-i]!=0)
		{
			if(i==m-i&&vis[i]<2) continue;
			cout<<i<<" "<<m-i;
			flag=true;
			break; 
		}
	}
	if(!flag)
		cout<<"No Solution";
}

two pointers

#include <iostream>
#include <algorithm>
using namespace std;

int n,m;
int value[200000];

int main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++)
		cin>>value[i];
	sort(value,value+n);
	bool flag=false;
	int i=0,j=n-1;
	while(i<j)
	{
		if(value[i]+value[j]==m)
		{
			cout<<value[i]<<" "<<value[j];
			flag=true;
			break;
		}
		else if(value[i]+value[j]>m)
			j--;
		else
			i++;
	}
	if(!flag)
		cout<<"No Solution";
}

【例】A1078 Hashing (25 分)

sequence n.序列
distinct a.有区别的
distinct positive integers 不重复的正整数
Quadratic a.二次的 n.二次方程式
probing n.探索
increment n.增量
collision n.碰撞,冲突

ATTENTION

  • 取模!!!
  • 结果其实可以直接输出,不用存在vector里。
#include <cstdio>
#include <vector>
#include <cmath>
using namespace std;

int mSize,n;
int num;
int hashList[10010]={0};
vector<int> ans;

bool isPrime(int n)
{
	if(n<=1) return false;
	int sqr=(int)sqrt(1.0*n);
	for(int i=2;i<=sqr;i++)
		if(n%i==0) return false;
	return true;
}
int main()
{
	scanf("%d %d",&mSize,&n);
	while(!isPrime(mSize))
		mSize++;
		
	for(int i=0;i<n;i++)
	{
		scanf("%d",&num);
		int pos;
		bool flag=false;
		for(int j=0;j<mSize;j++)
		{
			pos=(num+j*j)%mSize;
			if(hashList[pos]==0)
			{
				hashList[pos]=num;
				ans.push_back(pos);
				flag=true;
				break;
			}
		}
		if(!flag) ans.push_back(-1);
	}
	for(int i=0;i<ans.size();i++)
	{
		if(i!=ans.size()-1)
		{
			if(ans[i]==-1)
				printf("- ");
			else
				printf("%d ",ans[i]);
		}
		else
		{
			if(ans[i]==-1)
				printf("-");
			else
				printf("%d",ans[i]);
		}
	}
	return 0;
}

【例】A1145 Hashing - Average Search Time (25 分)

ATTENTION

  • 平方探测(只有正方向的):pos=(H(key)+k2)%TSize,0<=k<TSize
  • 如果根据平方探测,遇到一个为空的位置,说明该元素不在哈希表中,查找结束。如果遇到一个查找位置为空,也说明该元素不在哈希表中!
  • 元素的查找次数=冲突次数+1
  • 这道题再做还是觉得很奇怪…如果查遍了整个表,没有查到而且没有遇到空的,则不确定这个元素在不在表中,这时查找时间需要再+1(可能是与其他什么比较确定元素到底在不在表中?),但根据查找次数=冲突次数+1这个规则来看的确需要+1。不管怎样,先记住这个点吧…
#include <cstdio>

int msize,n,m;
int hash[10010]={0};

bool isPrime(int n) 	//素数问题 
{
	if(n<=1) 	return false;
	for(int i=2;i*i<=n;i++)
		if(n%i==0) return false;
	return true;
}
int main()
{
	scanf("%d %d %d",&msize,&n,&m);
	while(isPrime(msize)==false)
		msize++;
	for(int i=1;i<=n;i++)
	{
		int num;
		scanf("%d",&num);
		bool flag=false;
		for(int j=0;j<msize;j++)
		{
			int pos=(num+j*j)%msize;
			if(hash[pos]==0)
			{
				hash[pos]=num;
				flag=true;
				break;
			}
		}
		if(flag==false)
			printf("%d cannot be inserted.\n",num);
	}
	int sum=0;
	for(int i=0;i<m;i++)
	{
		int num;
		scanf("%d",&num);
		bool flag=false;
		for(int j=0;j<msize;j++)
		{
			flag=false;
			sum++;
			int pos=(num+j*j)%msize;
			if(hash[pos]==num)
			{
				flag=true;
				break;
			}
			else if(hash[pos]==0)
			{
				flag=true;
				break;
			}
		}
		if(!flag) sum++;
	}
	printf("%.1f",sum*1.0/m);
}

4.4 贪心

【例】A1038 Recover the Smallest Number

ATTENTION

  • 注意去0要在最后输出的时候去,并且只去除最开头的0。不能在中间输入各个段的时候去0,因为中间的0和开头的0不一样,中间的0不能去掉。
  • 本以为在排序后输出时,对于所有==0string都不输出就可以去掉所有的只含有0的段,实则不然,字符串中的“0”“00”“000”并不相等!!!
  • 注意去0后可能会出现输出为空的情况,这时候要输出“0”
  • 太妙了这思路啊啊啊啊啊!!!!!
#include <cstdio>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std; 

int n;
string str[20000];

bool cmp(string a,string b)
{
	return a+b<b+a;
}

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		string tmp;
		cin>>tmp; 	//
		str[i]=tmp;
	}
	sort(str,str+n,cmp);
	bool flag=true;
	for(int i=0;i<n;i++)
	{
		if(str[i]=="0"){}
		else
		{
			while(flag&&str[i][0]=='0')
				str[i].erase(0,1);
			if(str[i].size()!=0)
			 	flag=false;
			cout<<str[i];
		}
	}
	if(flag)
		cout<<"0";		
	return 0;
} 

改进:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int n;
string str[20000],s;

bool cmp(string a,string b){ return a+b<b+a; }

int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>str[i];
	sort(str,str+n,cmp);
	for(int i=0;i<n;i++)
		s+=str[i];
	while(s[0]=='0')
		s.erase(0,1);
	if(s.length()==0)
		cout<<"0";
	cout<<s;
	return 0;
}

【例】A1037 Magic Coupon (25 分)

coupons n.优惠券
bonus n.奖金;红利;额外津贴

ATTENTION

  • 遇到这种不能套算法的题有点不敢做…
  • 遇到不能对应算法的题目时,先自己思考一下~
  • 这道题本质就是给两串正负都有的数量不一定相等的数序列A和B,求A和B中元素的最大乘积和。
  • 注意还有0的情况,如果有一个乘数是0,那得到的也是0,不划算不划算。所以只计算最小的负数乘最小的负数和最大的正数乘最大的正数啦。
#include <cstdio>
#include <algorithm>
using namespace std;

int ans=0,nc,np;
int coupon[100010],value[100010];

int main()
{
	scanf("%d",&nc);
	for(int i=1;i<=nc;i++)
		scanf("%d",&coupon[i]);
	scanf("%d",&np);
	for(int i=1;i<=np;i++)
		scanf("%d",&value[i]);
	sort(coupon+1,coupon+nc+1);
	sort(value+1,value+np+1);
	int cne=0,pne=0,cpo=0,ppo=0;
	for(int i=1;i<=nc;i++)
	{
		if(coupon[i]<0)
			cne++;
		else
			break;
	}
	for(int i=nc;i>=1;i--)
	{
		if(coupon[i]>0)
			cpo++;
		else
			break;
		
	}
	for(int i=1;i<=np;i++)
	{
		if(value[i]<0)
			pne++;
		else
			break;
	}
	for(int i=np;i>=1;i--)
	{
		if(value[i]>0)
			ppo++;
		else
			break;
		
	}
	int n=min(cne,pne);
	for(int i=1;i<=n;i++)
		ans+=coupon[i]*value[i];
	n=min(cpo,ppo);
	for(int i=np,j=nc;i>np-n,j>nc-n;i--,j--)
		ans+=coupon[j]*value[i];
	printf("%d",ans);	
	return 0;
	
}

【例】A1067 Sort with Swap(0, i) (25 分)

ATTENTION

  • 只能与0交换
  • 需要注意到,要想要交换次数最少,那么最好的结果就是每次交换使得一个数能够回到它的位置。那么每次都拿0与本应在pos[0]这个位置的数进行交换。
  • 但是,如果在交换过程中,0不小心回到了0处,就需要与一个没有在他的位置的数交换,虽然这是一次无效交换,但如果拿0与已经回到位置的数进行交换,交换次数会更多。
  • 如果在0到达0处后遍历寻找与它交换的数,会超时,因为这个操作最坏时间复杂度为O(n2)。所以,应该在每次0与其他数交换的时候,就维护一个数,使他存储着一个不在位置上的数。这样最欢时间复杂度也只是O(n)
  • 有时候,看似简单的操作,时间复杂度会很高,但有时候,看似麻烦的操作,时间复杂度很低,所以在遇到超时的点的时候,要仔细考虑。
  • 贪心就是难啊哎…
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=100010;

int n,pos[maxn]={0},diff[maxn]={0};
int cnt,res=0;

int main()
{
	scanf("%d",&n);
	int tmp;
	for(int i=0;i<n;i++)
	{
		scanf("%d",&tmp);
		pos[tmp]=i;
		if(tmp!=i) cnt++;
	}
	int kmax=1;
	while(cnt)
	{
		res++;
		if(pos[0]!=0)
		{
			swap(pos[0],pos[pos[0]]); 	//交换 0 和 pos[0] 	
			cnt--;
			while(pos[kmax]==kmax) kmax++;
		}
		else if(pos[0]==0)
		{
			if(kmax>=n)
			{
				res--;
				break;
			}
			else
				swap(pos[0],pos[kmax]);
		}
	}
	printf("%d",res);
}

【例】A1070 Mooncake (25 分)

filling n. 填充;填料
crust n.外壳;面包皮;坚硬外皮
amount n. 数量,数额;总数
inventory n. 存货,存货清单;详细目录

ATTENTION

  • 题目里的价格是总价格不是单价。
  • 不能用while(d)求收益,可能包含了超市需求大于月饼总数量的情况。
  • 月饼的数量也得用double,注意题目里没有说明数量是整数!!!
#include <cstdio>
#include <algorithm>
using namespace std;

double sum=0;
int n,d;
struct Per{
	double price,ptot,cnt;
}mc[1010];
bool cmp(Per a,Per b)
{
	return a.price>b.price;
}
int main()
{
	scanf("%d %d",&n,&d);
	for(int i=0;i<n;i++)
	{
		scanf("%lf",&mc[i].cnt);
	}
	for(int i=0;i<n;i++)
	{
		scanf("%lf",&mc[i].ptot);
		mc[i].price=mc[i].ptot/mc[i].cnt;
	}
	sort(mc,mc+n,cmp);
	int idx=0;
	while(idx<n)
	{
		if(mc[idx].cnt<=d)
		{
			d-=mc[idx].cnt;
			sum+=mc[idx].ptot;
		}
		else if(mc[idx].cnt>d)
		{
			sum+=((double)(mc[idx].ptot*1.0)*(double)d/(double)mc[idx].cnt);
			d=0;
		}
		if(d==0)
		{
			break;
		}
		idx++;
	}
	printf("%.2f",sum);
	return 0;
 } 

【例】A1101 Quick Sort (25 分)

partition n.划分
typically v.通常
pivot n. 枢轴;中心点;中心

ATTENTION

  • 暴力有两个点会超时,虽然只能拿20分,但是如果是在考场上,先把20分拿到手,有时间再找方法。
  • 这道题有点像two pointers。既然对于每个点遍历一次判断其左边是否都小于它,其右边是否都大于它,那不如先遍历两遍整个数组,得到每个点左边的最大值和右边的最小值。注意首尾两个点要单独处理。
  • 很棒的题目,学到了!
  • 注意PAT中所有输出非单行的,都要加换行符。(这道题卡了一个点orz)
  • 果然英文题还是很有欺骗性的嗯。
//#include <cstdio>
//#include <algorithm>
//using namespace std;
//
//int n,idx=0;
//int num[100010];
//int sorted[100010];
//int res[100010];
//
//int main()
//{
//	scanf("%d",&n);
//	for(int i=0;i<n;i++)
//	{
//		scanf("%d",&num[i]);
//		sorted[i]=num[i];
//	}
//	sort(sorted,sorted+n);
//	if(sorted[0]==num[0])
//		res[idx++]=num[0];
//	int max=num[0];
//	for(int i=1;i<n;i++)
//	{
//		if(num[i]==sorted[i]&&max<num[i])
//			res[idx++]=num[i];
//		if(max<num[i])
//			max=num[i];
//	}
//	printf("%d\n",idx);
//	for(int i=0;i<idx;i++)
//	{
//		if(i==0)
//			printf("%d",res[i]);
//		else
//			printf(" %d",res[i]);
//	}
//	printf("\n");
//	return 0;
//}
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=100010;
int n,cnt=0;
int num[maxn],leftMax[maxn],rightMin[maxn],ans[maxn];

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&num[i]);
	fill(leftMax,leftMax+maxn,0);
	fill(rightMin,rightMin+maxn,1e9+10);
	int max=num[0],min=num[n-1]; 
	for(int i=1;i<=n;i++)
	{
		leftMax[i]=max;
		if(num[i]>max) max=num[i];
	}
	for(int i=n-2;i>=0;i--)
	{
		rightMin[i]=min;
		if(num[i]<min) min=num[i];
	}
	if(rightMin[0]>num[0]) ans[cnt++]=num[0];
	if(leftMax[n-1]<num[n-1]) ans[cnt++]=num[n-1];
	for(int i=1;i<n-1;i++)
	{
		if(num[i]>leftMax[i]&&num[i]<rightMin[i])
			ans[cnt++]=num[i];
	}
	sort(ans,ans+cnt);
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++)
	{
		if(i==0)
			printf("%d",ans[i]);
		else
			printf(" %d",ans[i]);
	}
	printf("\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值