第二、三周-周报

7-4 小孩子才做选择,大人全都要


分数 10
作者 陈越
单位 浙江大学


阿汪面前有两只盲盒,每只盒子打开都有两种可能:或者装了 X 克狗粮,或者是一只容量为 Y 克的狗粮储蓄盒。如果是狗粮,阿汪可以快乐地吃掉;如果是空储蓄盒,那就倒霉了,阿汪必须想办法找到狗粮把这只储蓄盒装满,自己还吃不到。

正当阿汪发愁不知道该怎么选的时候,铲屎官大手一挥:“小孩子才做选择,大人全都要!”但全都要的结果,却不一定是赚了还是亏了……

我们假设聪明的阿汪总是能嗅出狗粮最多的盒子,并且绝不会选任何储蓄盒。而铲屎官没有这样的鼻子,他一定是全都要。铲屎官如果打开了有储蓄盒的盒子,就必须想办法把储蓄盒装满,他会优先用另一只盒子里的狗粮装(如果另外一只盒子里有狗粮),不够了还得自己去买新的狗粮,这样阿汪可就亏啦,什么都吃不到了。本题就请你判断阿汪到底是赚了还是亏了。

输入格式:
输入在一行中给出两个整数,绝对值都不超过 100,中间用一个空格分开,分别代表两只盒子里的东西。如果是正数就表示是狗粮的份量,如果是负数就表示绝对值是空盆的容量。两个数都肯定不是 0,因为保证没有空盒子。

输出格式:
第一行输出两个结果:如果让阿汪选能吃到的狗粮 A,和如果铲屎官全都要能吃到的狗粮 B。两个数字间用一个空格分开。如果铲屎官的决定让阿汪赚到了,就在第二行输出一个笑脸 ^_^,否则输出一个哭脸 T_T。但如果反正什么都吃不到(两个盒子里都没有狗粮),就输出一张躺平脸 -_-。

输入样例 1:
12 18

输出样例 1:
18 30
^_^

输入样例 2:
12 -18

输出样例 2:
12 0
T_T

解析:

这道题需要注意几个点,1、阿汪只能选一个,铲屎官全都要.2、盒子可能全是储蓄盒子会输出和两个0,和-_-脸,或全是狗粮盒子,铲屎官的决定是赚的,输出最大数和他们的和^_^,或各一个,阿汪亏了,输出阿汪挑的正数,和铲屎官全都要得到的一个数,如果是负数就输出0。

代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
    int x1,x2,c,g;
    cin>>x1>>x2;
    if(x1<0&&x2<0){
        cout<<"0"<<" "<<"0"<<endl;
        cout<<"-_-";
    }
    else if(x1>0&&x2>0){
        g=x1>x2?x1:x2;
        c=x1+x2;
        cout<<g<<" "<<c<<endl<<"^_^";
    }
    else{
        g=x1>x2?x1:x2;
        c=x1+x2;
        if(c<0) c=0;
        cout<<g<<" "<<c<<endl<<"T_T";
    }
    return 0;
}

7-5 胎压监测


分数 15

全屏浏览

切换布局
作者 陈越
单位 浙江大学
小轿车中有一个系统随时监测四个车轮的胎压,如果四轮胎压不是很平衡,则可能对行车造成严重的影响。

让我们把四个车轮 —— 左前轮、右前轮、右后轮、左后轮 —— 顺次编号为 1、2、3、4。本题就请你编写一个监测程序,随时监测四轮的胎压,并给出正确的报警信息。报警规则如下:

如果所有轮胎的压力值与它们中的最大值误差在一个给定阈值内,并且都不低于系统设定的最低报警胎压,则说明情况正常,不报警;
如果存在一个轮胎的压力值与它们中的最大值误差超过了阈值,或者低于系统设定的最低报警胎压,则不仅要报警,而且要给出可能漏气的轮胎的准确位置;
如果存在两个或两个以上轮胎的压力值与它们中的最大值误差超过了阈值,或者低于系统设定的最低报警胎压,则报警要求检查所有轮胎。
输入格式:
输入在一行中给出 6 个 [0, 400] 范围内的整数,依次为 1~4 号轮胎的胎压、最低报警胎压、以及胎压差的阈值。

输出格式:
根据输入的胎压值给出对应信息:

如果不用报警,输出 Normal;
如果有一个轮胎需要报警,输出 Warning: please check #X!,其中 X 是出问题的轮胎的编号;
如果需要检查所有轮胎,输出 Warning: please check all the tires!。
输入样例 1:
242 251 231 248 230 20
输出样例 1:
Normal
输入样例 2:
242 251 232 248 230 10
输出样例 2:
Warning: please check #3!
输入样例 3:
240 251 232 248 240 10
输出样例 3:
Warning: please check all the tires!

解析:

需要有两个判断,1、轮胎是否与其中的最大值超过了阈值;2、轮胎是否低于了报警胎压;对于这两个如果有满足的情况就分别记录下来个数和它轮胎的编号。最后判断满足的轮胎个数;

代码:
#include<bits/stdc++.h>
using namespace std;

int main(){
    int max=0,x[4],xm,mi,xx,c=0,z=0;
    for(int i=0;i<4;i++) cin>>x[i];
    cin>>xm>>xx;
    for(int i=0;i<4;i++){
        if(max<x[i]) max=x[i];
        if(x[i]<xm) mi=i+1,c++;
    }
    for(int i=0;i<4;i++){
        if((max-x[i])>xx){
            mi=i+1;
            z++;
        }
    }
    if(c==0&&z==0){
        cout<<"Normal"<<endl;
    }
    else if((c>1||z>1)){
        cout<<"Warning: please check all the tires!"<<endl;
    }
    else{
        printf("Warning: please check #%d!\n",mi);
    }
    return 0;
}

7-6 吉老师的回归

分数 15

全屏浏览

切换布局

作者 DAI, Longao

单位 杭州百腾教育科技有限公司

曾经在天梯赛大杀四方的吉老师决定回归天梯赛赛场啦!

为了简化题目,我们不妨假设天梯赛的每道题目可以用一个不超过 500 的、只包括可打印符号的字符串描述出来,如:Problem A: Print "Hello world!"

众所周知,吉老师的竞赛水平非常高超,你可以认为他每道题目都会做(事实上也是……)。因此,吉老师会按照顺序看题并做题。但吉老师水平太高了,所以签到题他就懒得做了(浪费时间),具体来说,假如题目的字符串里有 qiandao 或者 easy(区分大小写)的话,吉老师看完题目就会跳过这道题目不做。

现在给定这次天梯赛总共有几道题目以及吉老师已经做完了几道题目,请你告诉大家吉老师现在正在做哪个题,或者吉老师已经把所有他打算做的题目做完了。

提醒:天梯赛有分数升级的规则,如果不做签到题可能导致团队总分不足以升级,一般的选手请千万不要学习吉老师的酷炫行为!

输入格式:

输入第一行是两个正整数 N,M (1≤M≤N≤30),表示本次天梯赛有 N 道题目,吉老师现在做完了 M 道。

接下来 N 行,每行是一个符合题目描述的字符串,表示天梯赛的题目内容。吉老师会按照给出的顺序看题——第一行就是吉老师看的第一道题,第二行就是第二道,以此类推。

输出格式:

在一行中输出吉老师当前正在做的题目对应的题面(即做完了 M 道题目后,吉老师正在做哪个题)。如果吉老师已经把所有他打算做的题目做完了,输出一行 Wo AK le

输入样例 1:

5 1
L1-1 is a qiandao problem.
L1-2 is so...easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so easy.

输出样例 1:

L1-4 is qianDao.

输入样例 2:

5 4
L1-1 is a-qiandao problem.
L1-2 is so easy.
L1-3 is Easy.
L1-4 is qianDao.
Wow, such L1-5, so!!easy.

输出样例 2:

Wo AK le

解析:

这道题需要查找"easy","qiandao",对于每道题可以用find函数来完成查找,如果没有找到字符串就将m减一,找到了就继续判断下一道题目,如果m小于0了那么就说明,吉老师遇到了该做却还没做完的题目直接输出该题目,如果循环结束了,m还没有小于0,输出“Wo AK le";

代码: 
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n,m,c=0;
    string a[30];
    cin>>n>>m;
    getchar();
    for(int i=0;i<n;i++) getline(cin,a[i]);
    for(int i=0;i<n;i++){
        if(a[i].find("qiandao")!=-1||a[i].find("easy")!=-1){
    		c++;
        }
        else{
            m--;
        }
        if(m<0){
		    cout<<a[i]<<endl;
		    return 0;
		}
    }
    cout<<"Wo AK le"<<endl;
    return 0;
}

7-7 静静的推荐

分数 20

全屏浏览

切换布局
作者 陈越
单位 浙江大学
天梯赛结束后,某企业的人力资源部希望组委会能推荐一批优秀的学生,这个整理推荐名单的任务就由静静姐负责。企业接受推荐的流程是这样的:

只考虑得分不低于 175 分的学生;
一共接受 K 批次的推荐名单;
同一批推荐名单上的学生的成绩原则上应严格递增;
如果有的学生天梯赛成绩虽然与前一个人相同,但其参加过 PAT 考试,且成绩达到了该企业的面试分数线,则也可以接受。
给定全体参赛学生的成绩和他们的 PAT 考试成绩,请你帮静静姐算一算,她最多能向企业推荐多少学生?

输入格式:
输入第一行给出 3 个正整数:N(≤10 
5
 )为参赛学生人数,K(≤5×10 
3
 )为企业接受的推荐批次,S(≤100)为该企业的 PAT 面试分数线。

随后 N 行,每行给出两个分数,依次为一位学生的天梯赛分数(最高分 290)和 PAT 分数(最高分 100)。

输出格式:
在一行中输出静静姐最多能向企业推荐的学生人数。

输入样例:
10 2 90
203 0
169 91
175 88
175 0
175 90
189 0
189 0
189 95
189 89
256 100
输出样例:
8
样例解释:
第一批可以选择 175、189、203、256 这四个分数的学生各一名,此外 175 分 PAT 分数达到 90 分的学生和 189 分 PAT 分数达到 95 分的学生可以额外进入名单。第二批就只剩下 175、189 两个分数的学生各一名可以进入名单了。最终一共 8 人进入推荐名单。

解析:

本题题意是说不低于天梯赛最低分175才能被选上,同时若PAT成绩超过指定分数都可以额外进入推荐名单,所以在输入学生分数时,可以将天梯赛不小于175的记录下来,同时如果他PAT的分数也不小于分数线那么就不让他占用批次直接可以推荐;之后将整理好的各个分数的人数与批次做对比,大于就只推荐批次人数,否则全推荐;

代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,k,s,a[291]={0},num=0;
    cin>>n>>k>>s;
    while(n--){
        int t,p;
        cin>>t>>p;
        if(t<175) continue;
        a[t]++;
        if(p>=s) a[t]--,num++;
    }
    for(int i=175;i<291;i++){
        if(a[i]<k) num+=a[i];
        else num+=k;
    }
    cout<<num;
    return 0;
}

7-10 简单计算器 


分数 25

全屏浏览

切换布局
作者 陈越
单位 浙江大学


本题要求你为初学数据结构的小伙伴设计一款简单的利用堆栈执行的计算器。如上图所示,计算器由两个堆栈组成,一个堆栈 S 
1

  存放数字,另一个堆栈 S 
2

  存放运算符。计算器的最下方有一个等号键,每次按下这个键,计算器就执行以下操作:

从 S 1

  中弹出两个数字,顺序为 n 1和 n 2;
从 S 2中弹出一个运算符 op;
执行计算 n2op n1;
将得到的结果压回 S 1。
直到两个堆栈都为空时,计算结束,最后的结果将显示在屏幕上。

输入格式:
输入首先在第一行给出正整数 N(1<N≤10 
3
 ),为 S 
1

  中数字的个数。

第二行给出 N 个绝对值不超过 100 的整数;第三行给出 N−1 个运算符 —— 这里仅考虑 +、-、*、/ 这四种运算。一行中的数字和符号都以空格分隔。

输出格式:
将输入的数字和运算符按给定顺序分别压入堆栈 S 
1

  和 S 
2

 ,将执行计算的最后结果输出。注意所有的计算都只取结果的整数部分。题目保证计算的中间和最后结果的绝对值都不超过 10 
9
 。

如果执行除法时出现分母为零的非法操作,则在一行中输出:ERROR: X/0,其中 X 是当时的分子。然后结束程序。

输入样例 1:
5
40 5 8 3 2
/ * - +
输出样例 1:
2
输入样例 2:
5
2 5 8 4 4
* / - +
输出样例 2:
ERROR: 5/0

解析:

本题需要用到栈stack将数字,符号全都压到不同的容器中,之后再用top取出,之后再删掉。注意除0时需要直接报错

代码:
#include<bits/stdc++.h>
using namespace std;
stack<int>s1,s2;
int n,s;
char op;
void solve(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>s;
		s1.push(s);
	}
	for(int i=0;i<n-1;i++){
		cin>>op;
		s2.push(op);
	}
	int w=-199,x;
	while(s2.size()!=0){
		int a,b;
		char p;
		a=s1.top();
		s1.pop();
		b=s1.top();
		s1.pop();
		p=s2.top();
		s2.pop();
		if(p=='+') x=a+b;
		else if(p=='-') x=b-a;
		else if(p=='*') x=a*b;
		else{
			if(a==0){
				w=b;
				break;
			}
			else{
				x=b/a;
			}
		}
		s1.push(x);
	}
	if(w==-199){
		cout<<x<<endl;
	}
	else{
		printf("ERROR: %d/0",w);
	}
}
int main(){
	solve();
	return 0;
}

L1-8 堆积木

分数 20

全屏浏览

切换布局

作者 DSA命题组

单位 成都信息工程大学

题目描述

yihan最近买了一箱积木,他想用这堆积木堆出近可能高的塔,但从箱子中取出的积木大小是不固定的,于是yihan想出来一个办法:

  • 现从箱子中取出一个积木,在现有的塔中寻找塔顶积木比它大且它与塔顶差值最小的塔,将它放置在塔顶。

  • 若同时出现多座塔的塔顶都比它大,且差值相同,则将这块积木放置在这些塔中最高的那座塔上。

  • 若高度也相同,则放置在最先搭建的塔上。

  • 若没找到满足条件的塔,就新建一座塔,让取出的积木成为新建的塔的塔顶

现在请你告诉yihan,能搭出最高的塔有多高,以及能搭出多少座积木塔。

输入格式:

输入在第一行有一个整数n(积木总个数),接下来一行,含有n个整数ai​(积木大小).( 1⩽n⩽ 104) ( 1⩽ai​⩽ 109)

输出格式:

输出两个整数a(塔最高几层),b(有多少塔)用空格隔开.

输入样例:

5
5 4 5 4 1

输出样例:

3 2

解析:

本题需要熟练的运用容器的使用,来模拟搭积木的过程,解题的关键数据是什么,运用过程见代码;

代码:
#include<bits/stdc++.h>
using namespace std;
vector<int>a,h;//h为塔高,a为最顶上的积木大小
int main(){
    int g,n;
    cin>>n>>g;
    a.push_back(g);
    h.push_back(1);
    n--;//第一次输入
    while(n--){
        cin>>g;
        int at=1e9,c,lg=0;
        for(int i=0;i<a.size();i++){
            if((a[i]>g)&&(a[i]-g)<at){//判断积木是否符合每个塔
                at=a[i]-g;
                c=i;//满足的记录下标
                lg=1;//只要进入了一个循环,就证明满足一个塔,记录
            }
            else if((a[i]-g)==at){//差值相等看塔高
                if(h[i]>h[c]){
                    c=i;
                }
            }
            else continue;
        }
        if(lg==1){//判断是否记录,记录了将积木加入到下标为c的容器中更新顶部,更新塔高
            a[c]=g;
            h[c]++;
        }
        else{//否则再建立个塔
            a.push_back(g);
            h.push_back(1);
        }
    }
    int max=0;
    for(int i=0;i<h.size();i++) if(h[i]>max) max=h[i];//找到最大塔
    cout<<max<<" "<<a.size();//塔的个数就是a的大小
    return 0;
}

7-2-8 古风排版

分数 20

全屏浏览

切换布局

作者 陈越

单位 浙江大学

中国的古人写文字,是从右向左竖向排版的。本题就请你编写程序,把一段文字按古风排版。

输入格式:

输入在第一行给出一个正整数N(<100),是每一列的字符数。第二行给出一个长度不超过1000的非空字符串,以回车结束。

输出格式:

按古风格式排版给定的字符串,每列N个字符(除了最后一列可能不足N个)。

输入样例:

4
This is a test case

输出样例:

asa T
st ih
e tsi
 ce s

解析:

本题题意 :将一段给定的字符串,按从左到右从上到下的顺序重新输出;通过发现每一列都有n个字符,所以可以对字符串下标从后往前取余数,余数相同的下标就在同一行,需要注意的是数组下标是从0开始的;如果一列不满足n个就从 (下标数/n+1)*n开始取余数,大于数组下标的部分输出空格。

代码:
#include<iostream>
using namespace std;
char a[2010];
string s;
int main(){
    int n;
    cin>>n;
    getchar();
    cin.getline(a,2010);
    int c=0,l;
    for(int i=0;a[i]!='\0';i++) c++;
    if(c%n==0) l=c/n;
    else{
        l=c/n+1;
    }
    for(int i=0;i<n;i++){
        for(int j=l*n-1;j>=0;j--){
            if(j%n==i){
                if(j>=c) cout<<" ";
                else{
                    cout<<a[j];
                }
            }
        }
        cout<<endl;
    }
    return 0;
}

7-6 外星人的一天

分数 15

全屏浏览

切换布局

作者 陈越

单位 浙江大学

地球上的一天是 24 小时。但地球上还有一些精力和勤奋度都远超一般人的大神级人物,他们的“一天”是以 48 小时为周期运转的,这种人被人们尊称为“外星人”。比如普通人的周一早 8:30 是外星人的周一早 4:15;普通人的周二早 9:21 是外星人的周一下午 4:40 —— 对外星人而言,一周的工作时间只有三天(即普通人的周一至周六),周日他们会蒙头大睡恢复体力,时间对他们是没有意义的。

在外星人眼里,地球人的时钟对他们而言实在是太不方便了。本题就请你为外星人们实现一款专用时钟。

输入格式:

输入在一行中给出一个不超过 10 的正整数 N,随后 N 行,每行给出一个地球人的时刻,格式为:Day hh:mm,其中Day是 [0,6] 区间内的整数,顺序代表周日至周六;hh是 24 小时制的小时数,是 [0,23] 区间内的整数;mm是分钟数,是 [0,59] 区间内的整数。

输出格式:

对输入的每一行地球人时刻,输出对应的外星人时间,格式与输入相同。其中Day在 [0,3] 区间内,对应周日到周三;分钟数若不是整数,则向下取整。注意:由于周日的时间对外星人没有意义,所以直接输出地球人的时间即可。

输入样例:

3
1 08:30
2 09:21
0 21:07

输出样例:

1 04:15
1 16:40
0 21:07

 解析:

分类讨论一定要做好,不然总会出现不知名的错误,有许多细节见代码。

代码:
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin>>n;
    while(n--){
        int day,h,m;
       scanf("%d %d:%d",&day,&h,&m);//按格式输入
       if(day==0){
        printf("%d %.02d:%02d\n",day,h,m);//星期天对外星人是没有意义的,直接输出
       }
       else{
        if(day%2==1){//判断天数
            day=day/2+1;
            if(h%2==1){
                m+=60;//不能整除需要对分钟加60;
            }
            m/=2;
            h/=2;
        }
        else{
            day/=2;
            h+=24;
            if(h%2==1){
                m+=60;
            }
            m/=2;
            h/=2;
        }
        printf("%d %.02d:%02d\n",day,h,m);//注意输出格式;
       }
    }
    return 0;
}

# [NOIP2010 普及组] 接水问题

## 题目描述

学校里有一个水房,水房里一共装有 $m$ 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 $1$。

现在有 $n$ 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 $1$ 到 $n$ 编号,$i$ 号同学的接水量为 $w_i$。接水开始时,$1$ 到 $m$ 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学 $j$ 完成其接水量要求 $w_j$ 后,下一名排队等候接水的同学 $k$ 马上接替 $j$ 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即 $j$ 同学第 $x$ 秒结束时完成接水,则 $k$ 同学第 $x+1$ 秒立刻开始接水。若当前接水人数 $n'$ 不足 $m$,则只有 $n'$ 个龙头供水,其它 $m - n'$ 个龙头关闭。

现在给出 $n$ 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。

## 输入格式

第一行两个整数 $n$ 和 $m$,用一个空格隔开,分别表示接水人数和龙头个数。

第二行 $n$ 个整数 $w_1,w_2,\ldots,w_n$,每两个整数之间用一个空格隔开,$w_i$ 表示 $i$ 号同学的接水量。

## 输出格式

一个整数,表示接水所需的总时间。

## 样例 #1

### 样例输入 #1

```
5 3
4 4 1 2 1
```

### 样例输出 #1

```
4
```

## 样例 #2

### 样例输入 #2

```
8 4
23 71 87 32 70 93 80 76
```

### 样例输出 #2

```
163
```

## 提示

【输入输出样例 \#1 说明】

第 $1$ 秒,$3$ 人接水。第 $1$ 秒结束时,$1,2,3$ 号同学每人的已接水量为 $1,3$ 号同学接完水,$4$ 号同学接替 $3$ 号同学开始接水。

第 $2$ 秒,$3$ 人接水。第 $2$ 秒结束时,$1,2$ 号同学每人的已接水量为 $2,4$ 号同学的已接水量为 $1$。

第 $3$ 秒,$3$ 人接水。第 $3$ 秒结束时,$1,2$ 号同学每人的已接水量为 $3,4$ 号同学的已接水量为 $2$。$4$ 号同学接完水,$5$ 号同学接替 $4$ 号同学开始接水。

第 $4$ 秒,$3$ 人接水。第 $4$ 秒结束时,$1,2$ 号同学每人的已接水量为 $4,5$ 号同学的已接水量为 $1$。$1,2,5$ 号同学接完水,即所有人完成接水的总接水时间为 $4$ 秒。

【数据范围】

$1 \le n \le {10}^4$,$1 \le m \le 100$,$m \le n$;

$1 \le w_i \le 100$。

NOIP2010 普及组 第二题

解析:

这道题之前在看贪心算法视频的时候,例题就差不多是这样,以至于我以为这也使一道贪心,但是这并不是-_-;这是一道简单的模拟题,其中要注意数组大小的问题,详见代码

代码:
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int n,m;
    cin>>n>>m;
    int a[21004];//不刚好10000的原因是因为k=m+n可能大于10000,这导致我一直90过不去;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int h=0,k=m;
    while(n){
        int min=1e9;
        for(int t=1;t<=m;t++){
            if(a[t]>0&&a[t]<min) min=a[t];//对正在接水的桶最小的值记录下来可以提高运算速度;
        }
        for(int i=1;i<=m;i++){
            a[i]-=min;//对每个正在接水的水桶,直接减去最少水桶的水量
            if(a[i]==0){
                k++;//这里是把数组开大的原因
                n--;
                a[i]=a[k];//对已经接完水的水龙头换人接//这可能会超过10000;
            }
        }
        h+=min;//加接水时间
    }
    cout<<h;
    return 0;
}

P2058 [NOIP2016 普及组] 海港 

题目背景

NOIP2016 普及组 T3

题目描述

小 K 是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。

小 K 对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第 �i 艘到达的船,他记录了这艘船到达的时间 ��ti​ (单位:秒),船上的乘客数 ��ki​,以及每名乘客的国籍 ��,1,��,2,…,��,�xi,1​,xi,2​,…,xi,k​。

小K统计了 �n 艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的 2424 小时(2424 小时 =86400=86400 秒)内所有乘船到达的乘客来自多少个不同的国家。

形式化地讲,你需要计算 �n 条信息。对于输出的第 �i 条信息,你需要统计满足 ��−86400<��≤��ti​−86400<tp​≤ti​ 的船只 �p,在所有的 ��,�xp,j​ 中,总共有多少个不同的数。

输入格式

第一行输入一个正整数 �n,表示小 K 统计了 �n 艘船的信息。

接下来 �n 行,每行描述一艘船的信息:前两个整数 ��ti​ 和 ��ki​ 分别表示这艘船到达海港的时间和船上的乘客数量,接下来 ��ki​ 个整数 ��,�xi,j​ 表示船上乘客的国籍。

保证输入的 ��ti​ 是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第 ��ti​ 秒到达海港。

保证 1≤�≤1051≤n≤105,∑��≤3×105∑ki​≤3×105 ,1≤��,�≤1051≤xi,j​≤105, 1≤��−1≤��≤1091≤ti−1​≤ti​≤109。

其中 ∑��∑ki​ 表示所有的 ��ki​ 的和。

输出格式

输出 �n 行,第 �i 行输出一个整数表示第 �i 艘船到达后的统计信息。

输入输出样例

输入 #1复制

3
1 4 4 1 2 2
2 2 2 3
10 1 3

输出 #1复制

3
4
4

输入 #2复制

4
1 4 1 2 2 3
3 2 2 3
86401 2 3 4
86402 1 5

输出 #2复制

3
3
3
4

说明/提示

【样例解释 1】

第一艘船在第 11 秒到达海港,最近 2424 小时到达的船是第一艘船,共有 44 个乘客,分别是来自国家 4,1,2,24,1,2,2,共来自 33 个不同的国家;

第二艘船在第 22 秒到达海港,最近 2424 小时到达的船是第一艘船和第二艘船,共有 4+2=64+2=6 个乘客,分别是来自国家 4,1,2,2,2,34,1,2,2,2,3,共来自 44 个不同的国家;

第三艘船在第 1010 秒到达海港,最近 2424 小时到达的船是第一艘船、第二艘船和第三艘船,共有 4+2+1=74+2+1=7 个乘客,分别是来自国家 4,1,2,2,2,3,34,1,2,2,2,3,3,共来自 44 个不同的国家。

【样例解释 2】

第一艘船在第 11 秒到达海港,最近 2424 小时到达的船是第一艘船,共有 44 个乘客,分别是来自国家 1,2,2,31,2,2,3,共来自 33 个不同的国家。

第二艘船在第 33 秒到达海港,最近 2424 小时到达的船是第一艘船和第二艘船,共有 4+2=64+2=6 个乘客,分别是来自国家 1,2,2,3,2,31,2,2,3,2,3,共来自 33 个不同的国家。

第三艘船在第 8640186401 秒到达海港,最近 2424 小时到达的船是第二艘船和第三艘船,共有 2+2=42+2=4 个乘客,分别是来自国家 2,3,3,42,3,3,4,共来自 33 个不同的国家。

第四艘船在第 8640286402 秒到达海港,最近 2424 小时到达的船是第二艘船、第三艘船和第四艘船,共有 2+2+1=52+2+1=5 个乘客,分别是来自国家 2,3,3,4,52,3,3,4,5,共来自 44个 不同的国家。

 解析:

大概题意,需要记录24小时内到达的乘客中有多少不同的国籍,每到达一艘船输出一次。本道题需要使用优先队列维护24小时内到达的游客的时间以及他的国籍,同时还要用map记录每个国籍的人数,运行过程见代码。

代码:
#include<bits/stdc++.h>
using namespace std;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;
map<int,int>mp;
int n;
void solve(){
int t,k;
    while(n--){
        cin>>t>>k;
        for(int i=0;;i++){
            if(q.size()!=0&&(t-86400>=q.top().first)){//将大于24小时的乘客处理
                mp[q.top().second]--;//对最上面的乘客国籍减掉
                if(mp[q.top().second]==0)//如果此国籍的游客为0,就将此国籍删掉
                mp.erase(q.top().second);
                q.pop();//将判断超过时间的游客推出
            }
            else{
                break;
            }
        }
        int x;
        for(int i=0;i<k;i++){
            cin>>x;
            mp[x]++;//对x国籍人数更新
            q.push({t,x});//时间和国籍存入优先队列
        }
        cout<<mp.size()<<endl;//map的大小就是国籍种类
    }
}   
int main(){
    cin>>n;
    solve();
    return 0;
}

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

能赢吗?会赢的

题目描述

gzhulc正在玩游戏,这个游戏有 nnn 个关卡,想要进行第 iii 关(除第 111 关外),就必须完成第 i−1i-1i−1 关。

其中第 iii 关有一个生命值为 aia_iai​ 的boss,同时当第 i−1i-1i−1(i≥2i \ge 2i≥2)关boss死亡时,第 iii 关boss会获得一个大小等同于 ⌈ai−12⌉\lceil \frac{a_{i-1}}{2} \rceil⌈2ai−1​​⌉ 的护盾值,gzhulc会永久提升 ⌊ai−12⌋\lfloor \frac{a_{i-1}}{2} \rfloor⌊2ai−1​​⌋ 的能力值。

gzhulc会在游戏开始时设置自己的能力值,当gzhulc的能力值严格大于boss的生命值加上护盾值时,gzhulc可以击杀boss。

但gzhulc在游戏开始时设置的能力值越高,代价越大,所以gzhulc想以最低的代价通过 nnn 个关卡,所以想问问你通过这 nnn 个关卡所需的最低的能力值是多少?

⌈x⌉\lceil x \rceil⌈x⌉:代表 xxx 的上取整,x=0.4x=0.4x=0.4,则 ⌈x⌉=1\lceil x \rceil = 1⌈x⌉=1, x=2.0x=2.0x=2.0,则 ⌈x⌉=2\lceil x \rceil = 2⌈x⌉=2。

⌊x⌋\lfloor x \rfloor⌊x⌋:代表 xxx 的下取整,x=1.9x=1.9x=1.9,则 ⌊x⌋=1\lfloor x \rfloor = 1⌊x⌋=1, x=0.4x=0.4x=0.4,则 ⌊x⌋=0\lfloor x \rfloor = 0⌊x⌋=0。

输入描述:

第一行输入两个整数 n (1≤n≤105)n\ (1 \leq n \leq 10^5)n (1≤n≤105),表示关卡数量。

第二行输入 nnn 个整数 a1,a2,…,an (1≤ai≤109)a_1, a_2, \ldots, a_n\ (1 \leq a_i \leq 10^9)a1​,a2​,…,an​ (1≤ai​≤109),表示每个关卡boss的生命值的大小。

输出描述:

输出一个整数,代表通过这 nnn 个关卡所需的最低的能力值。

示例1

输入

4
1 2 3 4

输出

5

 解析:

本题题意就是找到最小的能通关的能力值,因为数据比较大,我们采用二分查找来找答案;需要注意的是本题的怪物护盾向上取整和增加的能力值向下取整,!!!还有一个特别需要注意的一点,下一个怪物获得的护盾值为本个被打败的怪物的血量/2向上取整,!!不加这个怪物的护盾,这在样例是看不出来的。

代码:
#include<iostream>
using namespace std;
int a[100005],n;
bool slove(long long x){
    long long p=x,t;
    long long b[100005]={0};
    for(int i=0;i<n-1;i++){
        b[i]=b[i]+a[i];
        if(p<=b[i]) return false;//要绝对大于
        else{
            if(a[i]%2==0){//判断是否需要取整
                 t=a[i]/2;
                 p+=t;人加的能力值
                 b[i+1]+=t;//下个怪物要加的护盾
                 }
            else {
                t=a[i]/2;
                p+=t;
                b[i+1]=b[i+1]+t+1;
            }
        }
    }
    b[n-1]+=a[n-1];//为了不越界
    if(p>b[n-1]) return true;
    else return false;
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    long long r=1e18,l=0,mid;
    while(l<r){//二分查找
        mid=(l+r)/2;
        if(slove(mid)){
            r=mid;//因为要找满足条件的所以这不能加1,因为mid就是最小能力值
        }
        else{
            l=mid+1;
        }
    }
    cout<<r<<endl;
    return 0;
}

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

计算几何

题目描述

2023年赛季中,污渍与小夨相约,区域赛上一定要先看SUA的计算几何题,并且成功偷鸡;遗憾的是,赛季结束后,两人只能举起可乐向着一轮残月:“****,退钱!!!”;为了弥补遗憾,小夨决定出一道简单的计算几何题,并且期待赛场上的朋友们能够将其通过。

以上为题目背景;

给定 nnn 个点(编号 1∼n1\sim n1∼n),你可以进行若干次操作:选取任意两个不同的点连线;

保证线段两两不相交的前提下,至多可以有多少条线段?同时给出具体的连线方案。

输入描述:

第一行输入一个整数 n (1≤n≤100)n\ (1\leq n\leq 100)n (1≤n≤100),代表一共有 nnn 个点;

接下来输入 nnn 行,每行输入两个整数 xi,yi (0≤xi,yi≤106)x_i,y_i\ (0\leq{x_i,y_i}\leq{10^6})xi​,yi​ (0≤xi​,yi​≤106),表示点 iii 的坐标为 (xi,yi)(x_i,y_i)(xi​,yi​)。 

输出描述:

第一行输出一个整数 tottottot,代表至多可以有 tottottot 条线段;

接下来输出 tottottot 行;

每行输出两个正整数 id1,id2id_1,id_2id1​,id2​,分别表示每条线段的两个顶点对应的编号。

示例1

输入

复制3 0 0 1 1 3 0

3
0 0
1 1
3 0

输出

复制1 1 2

1
1 2

备注:

保证数据不存在相同坐标的点。

 解析:

这道题容易知道,最多连线的方法就是从左到右从上到下的点依次相连且个数为n/2,我们需要的就是输出正确的编号,如果是n奇数,最后一个坐标的

编号就不输出;

代码:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
struct bianhao{
    int x;
    int y;
}b[102];//用结构体记录编号,
int main(){
    int n,a[102];//a数组从大到小的坐标的编号;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>b[i].x>>b[i].y;
    }
    for(int j=1;j<=n;j++){
        int x1=1e9,y1=1e9,s,y2;
        for(int i=1;i<=n;i++){
            if(b[i].x<x1){
                x1=b[i].x;
                y1=b[i].y;
                s=i;
            }
            if(b[i].x==x1&&b[i].y<y1){
                y1=b[i].y;
                s=i;
            }
        }
        b[s].x=1e9;//将判断过后的最小编号赋予一个很大的值下次就不会判断它了;
        b[s].y=1e9;
        a[j]=s;
    }
    int c=0;
    if(n%2==1) c=1; 
    cout<<n/2<<endl;//输出线段数
    for(int i=1;i<=n-c;i++){//依次按格式输出编号;
        if(i%2==1){
            cout<<a[i]<<" ";
        }
        else{
            cout<<a[i]<<endl;
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值