目录
1 寝室分西瓜
小W排了很久的队买了好几个西瓜,西瓜的重量是整数斤的,他和室友们分着吃。非常喜欢偶数的他们决定把这些西瓜分别分成偶数斤的六份,现在考考你能不能按这种方式分这些西瓜?如果能分的话,最重的那一份比最轻的那一份最少多多少斤?
输入格式:
第一行一个正整数n表示西瓜的数量。
接下来n行每行一个正整数ai表示当前西瓜的重量。
输出格式:
输出n行。
如果第i个西瓜可以分成六份偶数斤就输出一个整数x表示分的最重的那一份比最轻的那一份最少多多少斤。
如果第i个西瓜不能这样分则输出-1。
输入样例:
在这里给出一组输入。例如:
2
14
15
输出样例:
在这里给出相应的输出。例如:
2
-1
样例解释1
第一个西瓜只有一个分法:分成2,2,2,2,2,4,最重的比最轻的多2斤。
第二个西瓜不能分成偶数斤的六份。
数据范围与提示
1≤n≤10
1≤ai≤100
思路:
若 n 为奇数(没法分偶数),或 n 小于 12(不够分偶数),输出 - 1
若 n 可以分,若 n 可以整除 12 ( n 可以每人分一样的一份),输出 0,若无法整除 12,则余数必为 2,因为题目意思为 最大值 与 最小值的 最小差值。
举例:16 % 12 = 4,可以分为 2 2 2 2 4 4,22 % 12 = 10,可以分为 2 4 4 4 4 4,总之只要不是-1的情况的无法整除12的数,一律输出 2
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N = 2e5+10;
int n, m;
int main()
{
int T;
scanf("%d", &T);
while(T -- )
{
int n;
scanf("%d", &n);
if( n%2 || n < 12)
{
printf("-1\n");
continue;
}
else
{
int res = 0;
if(n % 12 != 0) res = 2;
printf("%d\n", res);
}
}
return 0;
}
2 隔离警戒线
郑州封控了多个社区,现在把这些社区抽象成二维平面上的互不重叠的长方形,问你给这些社区拉警戒线需要多少单位长度的警戒线?
输入格式:
第一行一个正整数n表示封控社区的数量。
接下来n行每行四个正整数x1,y1,x2,y2(1≤x1<x2≤1e6,1≤y1<y2≤1e6)表示被封控社区的左下角坐标和右上角坐标。
输出格式:
输出一行一个正整数表示需要警戒线的长度。
输入样例:
3
2 1 4 3
4 1 6 3
3 3 5 5
输出样例:
20
样例解释
样例的三个封控地区如上所示,需要20单位长度的警戒线。
数据范围与提示
1≤n≤100
1≤x1<x2≤1e6,1≤y1<y2≤1e6
思路:
(1) 首先明确变量含义,x1y1为矩形左下点,x2y2为矩形右上点
(2) 计算总长度等于,每个小方框的周长 - 重合的边的长度,输入一个方框枚举一下与之前的方块是否重合,重合则减去重合边长
(3) 如何计算重合的长度?
两个方框有两种状态重合,举例
如图所示可化为重合的两种方式或
(此题不能变化,此例子帮助理解两种情况而已)
当 y 轴重合,即如上图所示的情况,第一种重合为 x1[ j ] == x2[ i ] ,第二种重合为 x1[ i ] == x2[ j ] ,计算重合的部分(红色部分)的长度,可如此计算(和 WAWA鱼大佬学习的方法),
两上边取最小值 - 两下边取最大值 ,再与零 取最值,代码解释为:
max(0, min(y2[i], y2[j]) - max(Y1[i], Y1[j]));
若两边无交集,则第二项为负数,如此则减去0,反之为正数,则减去重复的部分
对于 x 轴的重合部分亦是如此
max(0, min(x2[i], x2[j]) - max(x1[i], x1[j]));
详细代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N = 110;
int n, m;
int x1[N], Y1[N], x2[N], y2[N];
int main()
{
scanf("%d", &n);
int res = 0;
for(int i = 0; i < n; i ++ )
{
scanf("%d%d%d%d", &x1[i], &Y1[i], &x2[i], &y2[i]);
res += (x2[i] - x1[i]) * 2 + (y2[i] - Y1[i]) * 2;
}
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < i; j ++ )
{
if(x1[i] == x2[j] || x2[i] == x1[j])
res -= max(0, min(y2[i], y2[j]) - max(Y1[i], Y1[j]));
else if(Y1[i] == y2[j] || y2[i] == Y1[j])
res -= max(0, min(x2[i], x2[j]) - max(x1[i], x1[j]));
}
}
cout << res << endl;
return 0;
}
3 无接触水龙头
新冠疫情席卷全球已经两年有余,每个人都在为战胜这场灾难贡献自己的力量,希望这场灾难早日过去。
为了减少公共场所人与人间接接触的概率,大学生小D发明了一款自动洗手器。这款机器基于红外线感应的原理,用户只需要把手伸到水龙头下方即可自动出水,不需要再动手操作开关,这样就减少了病毒残留在开关处传播的风险。
小D这款设备的运行逻辑是:当设备的出水倒计时不为0时,水龙头会出水,并且倒计时随着时间减少。每当红外线感应器感应到有人伸手,就会将出水倒计时重置为t秒,出水倒计时为0秒时停止出水。
现在小D给了你感应器的记录列表,里面记录了在什么时间感应到了用户伸手,想请你计算在设备的运行过程中,总共流了多少秒的水。这样以便他对设备继续更新。
输入格式:
第一行两个整数n,t (1≤n≤105,1≤t≤109)分别表示记录的条数和仪器每次出水的时间。
其后n行,每行是一个时间,表示在该时刻感应到了用户使用该仪器。
时间的格式是 yyyy-MM-dd HH:mm:ss。其中y是年份,M是月份,d是日期,H是小时,m是分钟,s是秒数。 比如: 2022-05-08 01:12:34,表示:2022年5月8号1点12分34秒。
数据保证年份是2020年-2022年。
不保证时间的顺序。
输出格式:
输出一行一个整数,表示水龙头在运行过程中总的出水秒数。
输入样例:
2 10
2020-01-01 12:00:09
2020-01-01 12:00:00
输出样例:
19
思路:
预处理:
将输入的时间转化成秒来计算,此处可用二维数组把三年中的每一个月都表示出来(也可以表示平年的月份,再判断闰年),计算从2020-01-01到输入时间的时间差(单位:秒),排序时间差;
计算 res(结果):
两数的差与水龙头单词流水的时间(ll) 取 min ,最后再加上一个水龙头单次流水的时间,最后一次一定流完,输出结果即可
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N = 2e5+10;
int n, m;
int len[3] = {0, 366, 731};
int mon[3][13] = {{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
int main()
{
LL T, ll;
scanf("%lld %lld", &T, &ll);
LL time[N];
for(int i = 0; i < T; i ++ )
{
int year, m, d, hh, mm, ss;
scanf("%d-%d-%d %d:%d:%d", &year, &m, &d, &hh, &mm, &ss);
time[i] = len[year-2020] * 24 * 3600;
for(int j = 1; j < m; j ++ )
time[i] += mon[year-2020][j]*24*3600;
time[i] += (d-1) * 24 * 3600;
time[i] += hh*3600 + mm*60 + ss;
}
sort(time, time + T);
LL res = 0;
for(int i = 1; i < T; i ++ )
res += min((time[i] - time[i-1]), ll);
printf("%lld\n", res + ll);
return 0;
}
4 掷骰子
511寝室有6名同学,分别是小A,小B,小C,小D,小E和小F。由于每天吃盒饭,宿舍中产生了很多垃圾,所以他们需要每天都有人下去把全宿舍的垃圾都倒掉。
前六天,他们轮流下去倒垃圾(第一天是小A,第二天是小B....第六天是小F),一轮过后,他们感觉这样很无聊,所以从第七天开始,他们决定用掷骰子的方式,选出每天倒垃圾的人。
掷骰子的规则是:
每人每天掷出一个色子
1、如果有一个人点数最小且没有人与他并列,那么他就要去倒垃圾
2、否则,在色子点数并列最小的这些人中,选出幸运值最大的去倒垃圾。
定义x的幸运值为:x上一次倒垃圾的日子距离今天的天数。
(例如,小A在第七天的幸运值为6,因为他上一次去倒垃圾的日子是第1天)
现在给出这n天(从第7天到第n+6天)掷骰子的结果,请计算出这n天倒垃圾的人分别是谁。
输入格式:
第1行 一个整数n(n≤100),表示掷骰子的天数。
下面n行,每行6个数字,第i行为Ai Bi Ci Di Ei Fi,分别代表第i+6天每个人分别掷出的点数。保证点数为1~6之间的整数。
输出格式:
n行,每行一个字母。(ABCDEF其中的一个)
其中,第i行输出第i+6天去倒垃圾的人。
输入样例:
在这里给出一组输入。例如:
3
1 5 4 3 6 1
3 6 2 4 3 2
2 1 3 6 4 3
输出样例:
A
C
B
思路:
开一个 last 数组记录此人上一次的时间,找出本次的最小值,一个则直接算,多个则比较本次与上一次的相差天数,相差天数大的人先上,最后记得更新一下 倒垃圾人的 last 值
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N = 10;
int n, m;
int last[N] = {0, 1, 2, 3, 4, 5, 6};
int main()
{
int T;
scanf("%d", &T);
for(int tt = 7; tt < 7 + T; tt ++ )
{
int mi = 7, cnt = 1, x;
int a[N];
vector<int> b;
// 查找最小值的数值
for(int i = 1; i <= 6; i ++ )
{
scanf("%d", &a[i]);
if(a[i] < mi) mi = a[i];
}
// 查找最小值的人
for(int i = 1; i <= 6; i ++ )
if(mi == a[i]) b.push_back(i);
// 判断
int lmi = tt - last[b[0]];
int t = b[0];
for(int i = 1; i < b.size(); i ++ )
if( tt - last[b[i]] > lmi ) lmi = tt - last[b[i]], t = b[i];
// 更新 last
last[t] = tt;
printf("%c\n", 'A' + t - 1);
}
return 0;
}