外观
USACO 2025 US Open Contest, Bronze
[USACO25OPEN] Hoof Paper Scissors Minus One B
题目描述
在一局蹄子剪刀布游戏中,Bessie 和 Elsie 可以出
- 一种手势获胜,另一种失败。
- 两种手势平局。
蹄子剪刀布-1.0 的规则类似,但 Bessie 和 Elsie 可以各自出两个手势,每只蹄子出一个。在观察到她们所出的四个手势后,她们各自选择其中一个手势进行游戏。结果根据正常的蹄子剪刀布的规则决定。
给定 Elsie 计划在每局游戏中出的
输入格式
输入的第一行包含两个空格分隔的整数
以下
输出格式
输出
输入输出样例 #1
输入 #1
3 3
D
WD
LWD
1 2
2 3
1 11
2
3
4
5
6
7
2
3
4
5
6
7
输出 #1
0
0
51
2
3
2
3
说明/提示
在样例 1 解释:这对应于原始的蹄子剪刀布,我们可以设蹄子为
- 布 + 布
- 布 + 剪刀
- 布 + 蹄子
- 蹄子 + 布
- 剪刀 + 布
如果 Bessie 出这些组合中的任意一个,她可以确保通过出布来获胜。
测试点
: 。测试点
:没有额外限制。
解题思路
能让Bessie胜利的方式必须为如下的【L,R】
- 【胜利手势,其他手势(平局/失败)】
- 【其他手势(平局/失败),胜利手势】
- 【胜利手势,胜利手势】
所以找出能够战胜Elsie已给出两种手势的手势数量
然后根据公式统计出能胜利的最终手势组合数量:
代码示例
C++
#include<iostream>
#include<algorithm>
using namespace std;
int a[3005][3005];//a[i][j]=1,则代表手势i胜于手势j。
int main(){
int i,j,k,ans = 0;
int n,m;
char c;
cin >> n >> m;
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
cin >> c;
if(c == 'W'){
a[i][j] = 1;
}else if(c == 'L'){
a[j][i] = 1;
}
}
}
while(m--){
ans = 0;
cin >> j >> k;
for(i=1;i<=n;i++){
if(a[i][j] && a[i][k]) ans++;
}
cout << ans*(n*2-ans) << endl;
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[USACO25OPEN] More Cow Photos B
题目描述
今天奶牛们的心情特别顽皮!Farmer John 只是想拍摄一张奶牛们排成一行的照片,但她们总是在他得到机会按下快门之前移动位置。
具体地说,FJ 的
- 他希望奶牛们的身高先递增再递减。形式化地说,必须存在一个整数
使得 。 - 他不希望任何奶牛与另一头身高完全相同的奶牛相邻。形式化地说,对于所有
有 。 - 他希望照片是对称的。形式化地说,如果
,则 。
FJ 希望照片中包含尽可能多的奶牛。具体地说,FJ 可以移除一些奶牛并重新排列余下的奶牛。计算 FJ 在满足他的限制的情况下可以在照片中包含的奶牛的最大数量。
输入格式
你需要回答多个测试用例。 输入的第一行包含一个整数
每一个测试用例的第一行包含一个整数
输入保证所有测试用例的
输出格式
输出
输入输出样例 #1
输入 #1
2
4
1 1 2 3
4
3 3 2 11
2
3
4
5
2
3
4
5
输出 #1
3
11
2
2
说明/提示
对于第一个测试用例,FJ 可以选择身高为
- 测试点
: , 。 - 测试点
: ,所有奶牛的身高不超过 。 - 测试点
:没有额外限制。
解题思路
- 根据奶牛们的身高拥有以下三个性质,得出结论,奶牛的排列一定是先单调递增和在单调递减,且除了最高点的其他点都是对称出现,同一高度的点也只能出现两次(对称出现,递增一次,递减一次)。
。 有 。 ,则 。
- 利用数组占位思想,统计出相同高度出现的次数。
- 然后将最高的高度定义为照片的中心点,而照片的最左点从最低高度的牛开始,且该高度的牛必须出现两次才行,因为要对称。
代码示例
c++
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int a[100005] = {0};
int main(){
int i,j,k=0;
int t,n;
cin >> t;
while(t--){
memset(a,0,sizeof(a));
cin >> n;
for(i=1;i<=n;i++){
cin >> j;
a[j]++;
}
i=1,j=100000;
while(a[j]==0) j--;
k=1;
while(i<j){
if(a[i]>=2){
k+=2;
}
i++;
}
cout<<k<<endl;
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[USACO25OPEN] It's Mooin' Time III B
题目描述
Elsie 正在试图向 Bessie 描述她最喜欢的 USACO 竞赛,但 Bessie 很难理解为什么 Elsie 这么喜欢它。Elsie 说「现在是哞哞时间!谁想哞哞?请,我只想参加 USACO」。
Bessie 仍然不理解,于是她将 Elsie 的描述转文字得到了一个长为
一个三元组
- FJ 将字符串
在索引 处弯曲 90 度 - 该三元组的值是
的面积的两倍。
换句话说,该三元组的值等于
Bessie 向你进行
注意这个问题涉及到的整数可能需要使用 64 位整数类型(例如,C/C++ 中的 long long)。
输入格式
输入的第一行包含两个整数
以下
输出格式
对于每一个查询输出一行,包含对于该查询的答案。
输入输出样例 #1
输入 #1
12 5
abcabbacabac
1 12
2 7
4 8
2 5
3 101
2
3
4
5
6
7
2
3
4
5
6
7
输出 #1
28
6
1
-1
121
2
3
4
5
2
3
4
5
说明/提示
样例解释:对于第一个查询,
对于第四个查询,不存在满足
- 测试点
: 。 - 测试点
: ,唯一的询问满足 且 。 - 测试点
:没有额外限制。
解题思路
代码示例
c++
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int l[maxn][128], r[maxn][128];
char s[maxn]; // 定义字符数组s,用于存储输入的字符串
int main() {
int i,j,k;
int n,q;
char c,c2;
cin >> n >> q; // 读取字符串长度n和查询次数q
cin >> (s + 1); // 读取字符串s,从s[1]开始存储
for(i = 1; i <= n; i++) {
for(c = 'a'; c <= 'z'; c++) l[i][c] = l[i - 1][c]; // l[i][c]就是代表距离当前位置i左边最近字符c的位置是多少
l[i][s[i]] = i; // 更新当前字符s[i]字符出现的最新的位置
}
memset(r, 0x3f, sizeof(r)); // 将r数组初始化为一个较大的数,表示未找到字符
for(i = n; i >= 1; --i) {
if(i <= n - 1) {
for(c = 'a'; c <= 'z'; c++) r[i][c] = r[i + 1][c]; // r[i][c]就是代表距离当前位置i右边最近字符c的位置是多少
}
r[i][s[i]] = i;
}
// 处理每个查询
while(q--) {
int ql, qr; // 定义查询的左边界ql和右边界qr
cin >> ql >> qr; // 读取查询的左边界和右边界
ll ans = -1; // 初始化答案为-1,表示未找到合法的三元组
// 遍历每个可能的中间字符c
for(c = 'a'; c <= 'z'; c++) {
int k = l[qr][c]; // 找到字符c在右边界qr之后最后一次出现的位置
int i = n; // 初始化i为n,表示边界
// 找到字符c在左边界ql之前第一次出现的位置
for(c2 = 'a'; c2 <= 'z'; c2++) {
if(c2 == c) continue; // 如果c2等于c,跳过。因为i不能等于k
i = min(i, r[ql][c2]); // 找到一个最远左边界i
}
if(i >= k) continue; // 如果i大于等于k,说明没有找到合适的三元组,跳过
// 计算可能的三元组值(当直角三角形的两个直角边长度相等时,面积最大。)
int j1 = l[(i + k) / 2][c], j2 = r[(i + k) / 2][c];
if(j1 > i && j1 < k) ans = max(ans, ll(j1 - i) * (k - j1));
if(j2 > i && j2 < k) ans = max(ans, ll(j2 - i) * (k - j2));
}
cout << ans << '\n';
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
