A - Buttons
题目描述
有三个按钮A
,B
,C
,分别能被按A
,B
,C
次,其中按钮A
只能由人a
按下,按钮B
只能由人b
按下,按钮C
可以由任意一人按下,现在a
和b
轮流按按钮,a
先按,谁不能按按钮谁就输,问谁能赢。
思路:奇偶性
- 如果
C
是偶数,那么a
和b
都可以按C
按钮 C 2 \frac {C} {2} 2C次,那么就比A
和B
谁大,谁大谁赢,相等则B
赢,因为A
先按。- 如果
C
是奇数,那么a
可以多按一次C
,那么就比A+1
和B
谁大,谁大谁赢,相等则B
赢,因为A
先按。
public static void solve() throws IOException {
int a = readInt(), b = readInt(), c = readInt();
if (c % 2 == 0) {
if (a + c / 2 <= b + c / 2) {
printWriter.println("Second");
} else {
printWriter.println("First");
}
} else {
if (a + c / 2 + 1 > b + c / 2) {
printWriter.println("First");
} else {
printWriter.println("Second");
}
}
}
B - The Walkway
题目描述
有编号为 1 ∼ n 1 \sim n 1∼n的n
个长凳和m
个卖饼干的商人位于人行道附近,Petya
站在人行道的起点,他一定会经过这n
个长凳,由于走路太累,他会在以下任意一个条件满足时吃一块饼干。
- 在第
i
个长凳附近有一个卖饼干的人,那么Petya
会从卖饼干的人那里买一块饼干并立即吃掉。Petya
还没有吃饼干。然后Petya
会从背包中拿出一块饼干并立即吃掉(例如位于起点处)。- 距离
Petya
吃上一块饼干至少过去了d
分钟,Petya
会从背包中拿出一块饼干并立即吃掉。为了尽量减少
Petya
吃饼干的数量,你需要从m
个商人中移除一个商人。
求出吃饼干的最少数量 和 满足达到这个数量的移除商人的方案数。
输入样例
7 //测试数据的个数 6 2 2 2 5 8 3 2 3 5 8 10 4 9 2 8 9 10 30 5 8 6 8 15 24 29 30 5 8 6 8 12 20 27 8 8 3 1 2 3 4 5 6 7 8 2 2 2 1 2
输出样例
3 1 4 1 4 4 6 4 5 2 7 7 1 1
思路:技巧 + 模拟
- 先求出不移除任何商人所需要吃的饼干总数
- 再枚举移除第
i
个商人后需要吃的饼干,统计到map
中
public static void solve() throws IOException {
int n = readInt(), m = readInt(), d = readInt();
int[] cookies = new int[m + 5];
for (int i = 1; i <= m; i++) cookies[i] = readInt();
cookies[0] = 1 - d;//方便处理左边界,可以解决cookies[1] = 1的特殊情况
cookies[m + 1] = n + 1;//方便处理右边界
int sum = 0;
// 先求出不移除任何商人所需要吃的饼干总数
for (int i = 1; i <= m + 1; i++) {
// 技巧:多减一个1防止出现d的倍数导致sum多加一个1
// 例如 d=2,cookies=[2,6],第一个商人到第二个商人间实际只需要吃 4,6两块饼干
sum += (cookies[i] - cookies[i - 1] - 1) / d + 1;
}
sum--;//减去上面第 m+1处多加的一个饼干
Map<Integer, Integer> map = new HashMap<>();
// 枚举移除第 i个商人后需要吃的饼干
for (int i = 1; i <= m; i++) {
int cur = sum - 1;//减去在第 i个商人处的一个饼干
cur -= (cookies[i] - cookies[i - 1] - 1) / d;//减去在第 i-1~i个商人间的饼干
cur -= (cookies[i + 1] - cookies[i] - 1) / d;//减去在第 i~i+1个商人间的饼干
cur += (cookies[i + 1] - cookies[i - 1] - 1) / d;//加上第i-1~i+1个商人处的饼干
map.put(cur, map.getOrDefault(cur, 0) + 1);
}
int min = Integer.MAX_VALUE;
for (int p : map.keySet()) min = Math.min(min, p);
printWriter.println(min + " " + map.get(min));
}
C - Yet Another Permutation Problem
题目描述
Alex在玩一个游戏,给定 1 ∼ n 1 \sim n 1∼n的整数,将这些整数排成一个序列a
,对于序列中的第i
个数,计算得出 d i d_i di = gcd( a i a_i ai, a ( i m o d n ) + 1 a_{(i\ mod\ n) + 1} a(i mod n)+1),你所组成的排列最终得到的分数就是 d中不同数字的个数,要使得分数最高,应该组成怎样的排列?输出最终的排列(可能有多个,输出其一)。
输入样例
4 //测试数据的个数 5 2 7 10
输出样例
1 2 4 3 5 1 2 1 2 3 6 4 5 7 1 2 3 4 8 5 10 6 9 7
思路:模拟
- 让存在倍数关系的数字呆在一起
public static void solve() throws IOException {
int n = readInt();
Set<Integer> set = new HashSet<>();
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= n; i++) {
if (!set.contains(i)) list.add(i);
set.add(i);
int j = i;
//让存在倍数关系的数字呆在一起
while (2 * j <= n && !set.contains(2 * j)) {
set.add(2 * j);
list.add(2 * j);
j *= 2;
}
}
for (int p : list) printWriter.print(p + " ");
printWriter.println();
}