题目描述
IGMP
协议中,有一个字段称作最大响应时间 (MaxResponseTime
) ,HOST
收到查询报文,解折出 MaxResponsetime
字段后,需要在 (0,MaxResponseTime]
时间 (s
) 内选取随机时间回应一个响应报文,如果在随机时间内收到一个新的查询报文,则会根据两者时间的大小,选取小的一方刷新回应时间。
最大响应时间有如下计算方式:
- 当
MaxRespCode
<128
,MaxRespTime
=MaxRespCode
; - 当
MaxRespCode
≥128
,MaxRespTime
= (mant
|0x10
) << (exp
+3
);
注:exp
最大响应时间的高5~7
位,mant
为最大响应时间的低4
位。
其中接收到的 MaxRespCode
最大值为 255
,以上出现所有字段均为无符号数。
现在我们认为 HOST
收到查询报文时,选取的随机时间必定为最大值,现给出 HOST
收到查询报文个数 C
,HOST
收到该报文的时间 T
,以及查询报文的最大响应时间字段值 M
,请计算出 HOST
发送响应报文的时间。
输入描述
第一行为查询报文个数 C
,后续每行分别为 HOST
收到报文时间 T
,及最大响应时间 M
,以空格分割。
输出描述
HOST
发送响应报文的时间。
备注
用例确定只会发送一个响应报文, 不存在计时结束后依然收到查询报文的情况。
示例1
输入
3
0 20
1 10
8 20
输出
11
说明
收到3个报文,
- 第0秒收到第1个报文,响应时间为20秒,则要到0+20=20秒响应;
- 第1秒收到第2个报文,响应时间为10秒,则要到1+10=11秒响应,与上面的报文的响应时间比较获得响应时间最小为11秒;
- 第8秒收到第3个报文,响应时间为20秒,则要到8+20=28秒响应,与第上面的报文的响应时间比较获得响应时间最小为11秒;
最终得到最小响应报文时间为11秒
解析
本题考查逻辑模拟、位运算。
假设
- 在第 t1 秒收到第 1 个查询报文,最大响应时间为 m1,即最迟在第 t1 + m1 秒发送响应报文。
- 在第 t2 秒收到第 2 个查询报文,最大响应时间为 m2,即最迟在第 t2 + m2 秒发送响应报文。
- …
- 在第 tc 秒收到第 c 个查询报文,最大响应时间为 mc,即最迟在第 tc + mc 秒发送响应报文。
最后,我们需要选择 min(t1+m1,t2+m2,…,tc+mc) 时刻做发送响应报文的时间。
需要注意的是,本题收到的查询报文的最大响应时间 m
- 若 m < 128,则 m 可以直接当成最大响应时间
- 若 m ≥ 128,则需要取出 m 的二进制形式下的高 3~5 位作为 mant,低 4 位作为 exp,代入公式:(mant | 0x10) >> (exp + 3) ,公式结果为最大响应时间
那么如何取出 m 二进制形式下的高 3 ~ 5 位,以及低 4 位呢?
这里可以使用 “按位与&” 运算,按位与运算的特点是:进行计算的两个二进制数的对应位值都为1时,结果对应位的值才为1,否则为0。
比如:任何数 x 和二进制数 0000 1111 进行按位与的结果都是 x 二进制形式下低 4 位二进制的结果
0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | |
---|---|---|---|---|---|---|---|---|
& | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
同理,任何数 x 和二进制数 0111 0000 进行按位与的结果都是 x 二进制形式下高 3 ~ 5 位保留,其余位为0,如下图
0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | |
---|---|---|---|---|---|---|---|---|
& | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
由于本题需要保留高 3 ~ 5 位为新的二进制数,因此上面按位与结果二进制,还需要右移4位
0101 0000 >> 4 的结果位 0000 0101
源码实现
C
#include <stdio.h>
#include <limits.h>
#include <math.h>
int main() {
int c;
scanf("%d", &c);
int result = INT_MAX;
for (int i = 0; i < c; i++) {
int t, m;
scanf("%d %d", &t, &m);
if (m >= 128) {
int mant = m & 0b00001111;
int exp = (m & 0b01110000) >> 4;
m = (mant | 0x10) << (exp + 3);
}
result = (int) fmin(result, t + m);
}
printf("%d", result);
return 0;
}
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
int c;
cin >> c;
int result = INT_MAX;
for (int i = 0; i < c; i++) {
int t, m;
cin >> t >> m;
if (m >= 128) {
int mant = m & 0b00001111;
int exp = (m & 0b01110000) >> 4;
m = (mant | 0x10) << (exp + 3);
}
result = min(result, t + m);
}
cout << result;
return 0;
}
Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int c = sc.nextInt();
int result = Integer.MAX_VALUE;
for (int i = 0; i < c; i++) {
int t = sc.nextInt();
int m = sc.nextInt();
if (m >= 128) {
int mant = m & 0b00001111;
int exp = (m & 0b01110000) >> 4;
m = (mant | 0x10) << (exp + 3);
}
result = Math.min(result, t + m);
}
System.out.println(result);
}
}
Python
if __name__ == '__main__':
c = int(input())
result = float('inf')
for _ in range(c):
t, m = map(int, input().split())
if m >= 128:
mant = m & 0b00001111
exp = (m & 0b01110000) >> 4
m = (mant | 0x10) << (exp + 3)
result = min(result, t + m)
print(result)
JavaScript
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
const c = parseInt(await readline());
let result = Number.MAX_VALUE;
for (let i = 0; i < c; i++) {
let [t, m] = (await readline()).split(" ").map(Number);
if (m >= 128) {
const mant = m & 0b00001111;
const exp = (m & 0b01110000) >> 4;
m = (mant | 0x10) << (exp + 3);
}
result = Math.min(result, t + m);
}
console.log(result);
})();