[ZCMU OJ]5252: 英雄卡/5253: 排队接水/5254: 颜色叠加/5255: 勤劳的老杨/5256: 秘密大厦的访客

5252: 英雄卡

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 133  Solved: 12
[Submit][Status][Web Board]

Description

小李非常迷恋收集各种干脆面里面的英雄卡,为此他曾经连续一个月都只吃干脆面这一种零食,但是有些稀有英雄卡真的是太难收集到了。后来某商场搞了一次英雄卡兑换活动,只要你有三张编号连续的英雄卡,你就可以换一张英雄卡。小李想知道他最多可以换到几张英雄卡(新换来的英雄卡不可以再次兑换)。

Input

第一行,共一个整数n,表示小李拥有的英雄卡数。

第二行,共n个空格隔开的数字a[i],表示英雄卡的编号。

Output

输出仅有一行,共1个整数,表示小李最多可以换到的英雄卡。

Sample Input

6 3 1 2 4 4 5

Sample Output

1

HINT

1 2 3三张编号连续,可以换一张,换完后剩下4 4 5,不符合兑换规则,无法继续兑换。

 

数据规模:1<=a[i],n<=200000

---------------------------------------------------------------------------------------------------------------------------------

利用数组存储所有卡牌的数量,再利用循环找到三张连号的牌。 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(0);
	int a[200010]={0};
	int x;
	int n;
	cin>>n;
	int max_card=-1;
	for(int i=0;i<n;i++)
	{
		cin>>x;
		a[x]++;
		if(x>max_card)
		max_card=x;
	}	
	int duihuan=0;
	for(int i=0;i<max_card;i++)
	{
		if(a[i]>0)
		if(a[i+1]>0)
		if(a[i+2]>0)
		a[i]--,a[i+1]--,a[i+2]--,i--,duihuan++;
		//考虑到连号的牌可能有多张,所以i--返回再次查找 
	}
	cout<<duihuan<<endl;
}

5253: 排队接水

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 61  Solved: 9
[Submit][Status][Web Board]

Description

有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。

Input

输入共两行,第一行为n;第二行输入n个数字,表示第1个人到第n个人每人的接水时间T1,T2,……,Tn,每个数据之间有1个空格。

Output

输出有两行,第一行为一种排队顺序,第i个数字代表第i个接水人的编号,行末不能有多余空格,即1到n的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。

注意:输出排序时,当两人接水时间一样时,需要让编号小的人在前。

Sample Input

10 56 12 1 99 1000 234 33 55 99 812

Sample Output

3 2 7 8 1 4 9 6 10 5 291.90

HINT

N<=200000

1<=Ti<=10000000,ti有可能重复

---------------------------------------------------------------------------------------------------------------------------------

要让接水的平均时间最短,就要让总等待时间最短。那么就要进行排序,将接水所需等待时间短的人排在前面。我认为这道题的关键在于理解平均时间的计算。当第一个人在接水的时候,后面所有的人都在等第一个人接水。假如一共10个人,第一个人需要被等待1分钟,那么后面9个人都需要花费1分钟的等待时间,所以总等待时间应该加上9分钟。

#include<bits/stdc++.h>
using namespace std;
struct person
{
	int id;
	int time;
}per[200010];
bool cmp(person a,person b)
{
	if(a.time==b.time)
	return a.id<b.id;
	return a.time<b.time;
}
int main()
{
    ios::sync_with_stdio(0);
	long long n;//long long重点 
	cin>>n;
	long long a[n];//long long重点 
	for(int i=0;i<n;i++)
	{
		cin>>per[i].time;
		per[i].id=i+1;
	}
	sort(per,per+n,cmp);
	double sum=0;
	for(int i=0;i<n;i++)
	{
		if(i==0)
		cout<<per[i].id;
		else
		cout<<" "<<per[i].id;
		
		sum+=per[i].time*(n-i-1);
	}
	cout<<endl;
	printf("%.2lf\n",sum/n);
}

5254: 颜色叠加

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 145  Solved: 23
[Submit][Status][Web Board]

Description

热爱科学的Kimi这段时间在研究各种颜色,今天他打算做一个关于颜色叠加的小实验。 Kimi有很多张蓝色和黄色的长方形透明塑料卡片。众所周知,如果把蓝色和黄色混合在一起就会变成绿色。因此,Kimi对着光观察蓝色透明卡片和黄色透明卡片的叠加部分也就可以看到绿色啦。 假设在一个二维平面中,一张蓝色的透明卡片和一张黄色的透明卡片都与坐标轴平行放置,即卡片的横边与 x 轴平行,竖边与 y 轴平行。 现在给出一张蓝色卡片和一张黄色卡片的左上角坐标(均为整数)以及两张卡片的长和宽(均为正整数)。

注意:此处定义与 x 轴平行的那组边为长边,与 y 轴平行的那组边为宽边。

请编写一个程序计算这两张卡片叠加后所形成的绿色区域的面积。

Input

单组输入。 第 1 行输入四个整数,分别表示蓝色长方形透明卡片的左上角坐标( x 坐标和 y 坐标)、长和宽。两两之间用英文空格隔开。 第 2 行输入四个整数,分别表示黄色长方形透明卡片的左上角坐标( x 坐标和 y 坐标)、长和宽。两两之间用英文空格隔开。 两张长方形透明卡片的 x 坐标和 y 坐标的取值范围为[-1000, 1000],长和宽的取值范围为[1,200]。

Output

输出一个非负整数,表示两张卡片叠加后所形成的绿色区域的面积。

Sample Input

0 100 200 100 100 150 75 75

Sample Output

1875

---------------------------------------------------------------------------------------------------------------------------------

这道题粗略估计时间复杂度之后我选择用二维数组暴力循环来做,这样就避免了各种情况的分类讨论。

#include<bits/stdc++.h>
using namespace std;
int a[2410][2410]={0};
int main()
{
	ios::sync_with_stdio(0);
	int x1,y1,x2,y2;
	int c1,k1,c2,k2;
	
	cin>>x1>>y1>>c1>>k1;
	cin>>x2>>y2>>c2>>k2;
	
	for(int i=x1;i<x1+c1;i++)
	//for(int j=y1;j<y1+k1;j++)
	for(int j=y1-k1+1;j<=y1;j++)
	{
		a[i+1200][j+1200]++;
	}
	
	for(int i=x2;i<x2+c2;i++)
	//for(int j=y2;j<y2+k2;j++) 
	for(int j=y2-k2+1;j<=y2;j++)
	{
		a[i+1200][j+1200]++;
	}
	int area=0;
	for(int i=0;i<2410;i++)
	{
		for(int j=0;j<2410;j++)
		{
			if(a[i][j]==2)
			area++;
		}
	}
	cout<<area<<endl;
}

5255: 勤劳的老杨

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 26  Solved: 6
[Submit][Status][Web Board]

Description

勤劳的老杨最近收到了一个任务清单,在这个清单上有 n​ 项不同的工作任务。对于每一项任务都给出了两个时间 [x,y] ,其中 x 表示任务的起始时间(任务从第 x 天开始,包含第 x 天),y 表示任务的结束时间(任务到第 y 天结束,包含第 y 天)。 认真的老杨对待每一项任务都是一心一意的。一旦他决定做某一项任务,在该任务没有完成之前他不会同时再做另一项任务,也就是说在任意时刻老杨手头最多只有一项任务。 假设完成每一项任务所获得的报酬都是相等的。那么,老杨应该如何来安排自己的时间才可以得到最多的报酬呢? 请你编写一个程序帮老杨计算出他最多可以完成的任务数量。保证至少能完成一项任务。

Input

单组输入。

第 1 行输入一个正整数 n(n<=200000) 表示任务清单上任务的总数。

第 2 行到第 n+1 行每一行包含两个正整数x,y ,分别表示每一项任务的开始时间和结束时间,两个正整数之间用空格隔开,保证 1<= x,y<=10^9。

Output

输出老杨最多可以完成的任务数量。

Sample Input

7

1 4

1 3

2 7

3 4

4 6

5 10

7 8

Sample Output

3

HINT

对于输入样例,最多可以完成的任务数量为 3,对应 [1, 3] (第 2 项任务),[4, 6] (第 5 项任务)和 [7, 8] (第 7 项任务)这三项任务。

---------------------------------------------------------------------------------------------------------------------------------

选择越早结束的任务去完成,这样选择下一个任务就有更多的余地,这样就可以使完成任务的件数最大化。将任务定义为结构体,并依据任务结束时间进行升序排序。在选择任务的时候,根据下一个任务的开始时间是否大于本任务的结束时间来判断是否选择下一个任务。

#include<bits/stdc++.h>
using namespace std;
struct task
{
	int b;
	int e;
}t[200010];
bool cmp(task a,task b)
{
	return a.e<b.e;
}
int main()
{
    ios::sync_with_stdio(0);
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	cin>>t[i].b>>t[i].e;
	
	sort(t,t+n,cmp);
	
	int temp=0;
	int sum=0;
	for(int i=0;i<n;i++)
	{
		if(t[i].b>temp)
		temp=t[i].e,sum++;
	}
	cout<<sum<<endl;
}

5256: 秘密大厦的访客

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 668  Solved: 56
[Submit][Status][Web Board]

Description

Kimi最近在负责一栋秘密大厦的安保工作,他的工作是记录大厦的来访者情况。

每个来访者都有一个与之对应的唯一编号,在每一条到访记录中记录了该来访者的编号。

现在Kimi需要统计每一条记录中的来访者是第几次光临秘密大厦。

Input

单组输入,包含两行。

第1行包含一个正整数 n,表示记录的条数;

第2行包含 n 个正整数,依次表示Kimi的记录中每位来访者的编号,两两之间用空格隔开。

保证 n 与来访者的编号都不超过 200000。

Output

输出 1 行,包含 n 个正整数,两两之间用空格隔开,依次表示每条记录中的来访者编号是第几次出现。

Sample Input

6

1 1 2 2 3 1

Sample Output

1 2 1 2 1 3

---------------------------------------------------------------------------------------------------------------------------------

建立一个数组用以存储数字出现次数,再将所有数字依次存入数组,存入一次就输出一次出现次数即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(0);
	int n;
	cin>>n;
	int a[200010]={0};
	int x;
	for(int i=0;i<n;i++)
	{
		cin>>x;
		a[x]++;
		if(i==0)
		cout<<a[x];
		else
		cout<<" "<<a[x];
	}
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值