2022 . 11 . 26测试赛
[USACO21DEC] Lonely Photo B
题目描述
Farmer John 最近购入了 N N N 头新的奶牛( 3 ≤ N ≤ 5 × 1 0 5 3 \le N \le 5 \times 10^5 3≤N≤5×105),每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。
奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。 然而,他不想拍摄这样的照片,其中只有一头牛的品种是更赛牛,或者只有一头牛的品种是荷斯坦牛——他认为这头奇特的牛会感到孤立和不自然。 在为每个连续不少于三头奶牛的序列拍摄了一张照片后,他把所有「孤独的」照片,即其中只有一头更赛牛或荷斯坦奶牛的照片,都扔掉了。
给定奶牛的排列方式,请帮助 Farmer John 求出他会扔掉多少张孤独的照片。如果两张照片以不同的奶牛开始或结束,则认为它们是不同的。
输入格式
输入的第一行包含 N N N。
输入的第二行包含一个长为 N N N 的字符串。如果队伍中的第 i i i 头奶牛是更赛牛,则字符串的第 i i i 个字符为 G。否则,第 i i i 头奶牛是荷斯坦牛,该字符为 H。
输出格式
输出 Farmer John 会扔掉的孤独的照片数量。
样例 #1
样例输入 #1
5
GHGHG
样例输出 #1
3
提示
【样例解释】
这个例子中的每一个长为 3 的子串均恰好包含一头更赛牛或荷斯坦牛——所以这些子串表示孤独的照片,并会被 Farmer John 扔掉。所有更长的子串(GHGH、HGHG 和 GHGHG)都可以被接受。
【数据范围】
- 测试点 2-4 满足 N ≤ 50 N \le 50 N≤50。
- 测试点 5-10 满足 N ≤ 5000 N \le 5000 N≤5000。
- 测试点 11 没有额外限制。
注意这个测试点的答案可能无法用标准的 32 位整数型存储,你可能需要使用更大的整数类型(例如,C++ 中 64 位的 “long long int” 类型)。
思路1
90pts
O
(
n
2
)
O(n^2)
O(n2) 模拟 枚举左端点 但算法过不了苛刻的第11个测试点
代码1
#include <bits/stdc++.h>
using namespace std;
string s;
long long n , ans;
int main() {
cin >> n >> s;
int t = s.size();
for(int i = 0; i < t; ++i){
int g = 0 , h = 0;
for(int j = i; j < t; ++j){
if(s[j] == 'H')
h++;
else
g++;
if(g + h >= 3)
if(g == 1 || h == 1)
ans++;
}
}
cout << ans << endl;
return 0;
}
思路2
定义四个数组 LG , RG , 分别表示每个H和每个G左右相邻连续不变的不同字符
以每个字符为每张照片的左端点和右端点 , 然后统计每个以此字符为中间的照片数量
(ans += LG[i] * RG[i]
因为如果这个字符是被两种不同的字符夹杂在中间 则代表数组两边都不为零
代码2
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 5e5 + 10;
string s;
int n , l = 1 , r = 1 , ans , LG[MAXN] , RG[MAXN] , LH[MAXN] , RH[MAXN];
//LG 每个H字符左侧连续相邻字符数量 RG(右侧), LH , RH 同上
signed main(){
// freopen("lonelyphoto.in" , "r" , stdin);
// freopen("lonelyphoto.out" , "w" , stdout);
cin >> n >> s;
s = " " + s;//使首字符地址为是s[i]便于同数组进行计算
for(int i = 2; i <= n; i++)
LG[i] = s[i - 1] == 'G' ? LG[i - 1] + 1 : 0; // 三目运算符如果 s[i - 1] 是 G 则返回LG[i - 1] + 1,否则返回 0
for(int i = n - 1; i >= 1; i--)//同上
RG[i] = s[i + 1] == 'G' ? RG[i + 1] + 1 : 0;
for(int i = 2; i <= n; i++)
LH[i] = s[i - 1] == 'H' ? LH[i - 1] + 1 : 0;
for(int i = n - 1; i >= 1; i--)
RH[i] = s[i + 1] == 'H' ? RH[i + 1] + 1 : 0;
for(int i = 1; i <= n; i++){
if(s[i] == 'H'){
if(LG[i]) ans += LG[i - 1];
if(RG[i]) ans += RG[i + 1];
ans += LG[i] * RG[i];//如果ans加的不是0则代表这个 H 字符被夹在 G 字符 中间
}
else{//同上
if(LH[i]) ans += LH[i - 1];
if(RH[i]) ans += RH[i + 1];
ans += LH[i] * RH[i];
}
}
cout << ans << endl;
// fclose(stdin);
// fclose(stdout);
return 0;
}
思路3
稍微优化一下时间和空间,使算法不再那么有太多赘述
上述思路可以进行优化 , 只定义一个数组代表连续相邻的字符数目
如 GGGHHGGHGGG 则为c[] = {0 , 3 , 2 , 2 , 1 , 3};
而答案统计可以直接特殊处理首数据和尾数据,然后思路相同 , 统计以此字符为首端点和尾端点,如果是一个字符则放在任何一个无相同字符的照片都可以构成孤独的照片处理一下
注意 , 此种算法需要特判全部为H或者全部为G情况,否则会输出-2
代码3
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 5e5 + 10;
string s;
int n , c[MAXN];
signed main(){
// freopen("lonelyphoto.in" , "r" , stdin);
// freopen("lonelyphoto.out" , "w" , stdout);
int p = 0 , temp = 1;
cin >> n >> s;
for(int i = 1; i < n; ++i){
if(s[i] == s[i - 1])
temp++;
else
c[++p] = temp , temp = 1;
}
c[++p] = temp;
int ans = 0;
//开头和结尾进行特殊处理
ans += c[2] != 0 ? c[2] - 1 : 0;//避免全部为 G 或 全部 为 H 情况 出现
ans += c[p - 1] != 0 ? c[p - 1] - 1 : 0;
for(int i = 2; i < p; ++i){
ans += c[i - 1] + c[i + 1] - 2; // 以此字符为开头或结尾的情况
if(c[i] == 1)
ans += c[i - 1] * c[i + 1]; // 若此字符是被两种连续不同的字符夹着则可以以此字符为中间用乘法原理加上;
}
cout << ans << endl;
// fclose(stdin);
// fclose(stdout);
return 0;
}
[USACO22JAN] Herdle B
题目描述
奶牛们发明了一种名为 Herdle 的新型解谜游戏,在牛界引起了轰动。
每天都会有一个新谜题发布供奶牛解决。游戏采用 3 × 3 3\times 3 3×3 方阵的形式表示农场的一块田地,田地的每个方格都由特定品种的奶牛占据。总共只有 26 26 26 种可能的品种,每一种由 A \text{A} A 到 Z \text{Z} Z 中的不同大写字母标识。玩家不会被告知田地中的奶牛品种排列方式——游戏目标是通过一系列猜测确定它们。
每次猜测,奶牛们输入一个 3 × 3 3\times 3 3×3 的大写字母方阵,表示该田地可以用奶牛填充的可能方式。猜测的某些方格可能是正确的。这些方格以绿色高亮显示,让奶牛们知道这些是正确的。猜测的另一些方格可能填入了品种正确但位置错误的奶牛。这些以黄色高亮显示。
黄色高亮显示的方格的数量可以帮助指示某个品种的奶牛数量。 例如,假设猜测方阵包含 4 4 4 头品种 A \text{A} A 的奶牛,而答案方阵包含 2 2 2 只品种 A \text{A} A 的奶牛,其中没有正确位置上的 A \text{A} A (即,它们都不应该是绿色的)。 在这种情况下,猜测方阵中只有两个 A \text{A} A 应以黄色高亮显示。 更准确地说,如果猜测方阵中有 x x x 个特定品种的奶牛,并且 答案方阵中有 y ≤ x y \le x y≤x 头该品种奶牛(不包括位置正确而得到绿色高亮显示的奶牛),那么猜测方阵的 x x x 头奶牛中只有 y y y 头奶牛应该以黄色高亮显示。
给定正确答案的方阵和一个表示对该答案的猜测的方阵,请计算绿色和黄色高亮显示的方格的数量。
输入格式
输入的前 3 行给定了正确答案的方阵。以下 3 行表示对该答案的猜测。
输出格式
输出两行。输出的第一行包含应当以绿色高亮显示的方格的数量。输出的第二行包含应当以黄色高亮显示的方格的数量。
样例 #1
样例输入 #1
COW
SAY
MOO
WIN
THE
IOI
样例输出 #1
1
1
样例 #2
样例输入 #2
AAA
BBB
CCC
AYY
AAA
ZZZ
样例输出 #2
1
2
提示
【样例解释 1】
在这个例子中,最后一行中间的 O 是正确的,所以这个方格以绿色高亮显示。字母 W 位于错误的位置,所以它以黄色高亮显示。
【样例解释 2】
在这里,其中一个 A 位于正确的位置,所以它以绿色高亮显示。余下的 A 均不在正确位置上,由于答案方阵中有两个 A,所以有两个 A 应当以黄色高亮显示。
思路
用三个 map 统计原矩阵和正确矩阵中各字符的个数,以及每个已经被统计为绿色位置的字符数量
黄色是字符就是原矩阵和正确矩阵都减去被统计为绿色后的更小值
代码
#include <bits/stdc++.h>
using namespace std;
map <char , int> mp1;
map <char , int> mp2;
map <char , int> mp3;
string s1[4] , s2[4];
long long n , ans;
int main() {
// freopen("herdle.in" , "r" , stdin);
// freopen("herdle.out" , "w" , stdout);
cin >> s1[1] >> s1[2] >> s1[3] >> s2[1] >> s2[2] >> s2[3];
for(int i = 1; i <= 3; ++i)
for(int j = 0; j <= 2; ++j)
mp1[s1[i][j]]++ , mp2[s2[i][j]]++;
for(int i = 1; i <= 3; ++i)
for(int j = 0; j <= 2; ++j)
if(s1[i][j] == s2[i][j])
ans++ , mp3[s1[i][j]]++;
cout << ans << endl;
ans = 0;
for(char i = 'A'; i <= 'Z'; ++i){
if(mp2[i] | mp1[i]){//此或操作为了防止有数量为0的字符,实际上是个多余的操作
mp1[i] -= mp3[i];//将此操作删去也可AC
mp2[i] -= mp3[i];
ans += min(mp1[i] , mp2[i]);
}
}
cout << ans << endl;
return 0;
// fclose(stdin);
// fclose(stdout);
}
[USACO21DEC] Air Cownditioning B
题目描述
Farmer John 的 N N N 头奶牛对他们牛棚的室温非常挑剔。有些奶牛喜欢温度低一些,而有些奶牛则喜欢温度高一些。
Farmer John 的牛棚包含一排 N N N 个牛栏,编号为 1 … N 1 \ldots N 1…N,每个牛栏里有一头牛。 第 i i i 头奶牛希望她的牛栏中的温度是 p i p_i pi,而现在她的牛栏中的温度是 t i t_i ti。为了确保每头奶牛都感到舒适,Farmer John 安装了一个新的空调系统。该系统进行控制的方式非常有趣,他可以向系统发送命令,告诉它将一组连续的牛栏内的温度升高或降低 1 个单位——例如「将牛栏 5 … 8 5 \ldots 8 5…8 的温度升高 1 个单位」。一组连续的牛栏最短可以仅包含一个牛栏。
请帮助 Farmer John 求出他需要向新的空调系统发送的命令的最小数量,使得每头奶牛的牛栏都处于其中的奶牛的理想温度。
输入格式
输入的第一行包含 N N N。下一行包含 N N N 个非负整数 p 1 … p N p_1 \ldots p_N p1…pN,用空格分隔。最后一行包含 N N N 个非负整数 t 1 … t N t_1 \ldots t_N t1…tN。
输出格式
输出一个整数,为 Farmer John 需要使用的最小指令数量。
样例 #1
样例输入 #1
5
1 5 3 3 4
1 2 2 2 1
样例输出 #1
5
提示
【样例解释】
一组最优的 Farmer John 可以使用的指令如下:
初始温度 :1 2 2 2 1
升高牛棚 2..5:1 3 3 3 2
升高牛棚 2..5:1 4 4 4 3
升高牛棚 2..5:1 5 5 5 4
降低牛棚 3..4:1 5 4 4 4
降低牛棚 3..4:1 5 3 3 4
【数据范围】
- 测试点 2-5 满足 N ≤ 100 N \leq 100 N≤100。
- 测试点 6-8 满足 N ≤ 1000 N \leq 1000 N≤1000。
- 测试点 9-10 满足 N ≤ 100 , 000 N \leq 100,000 N≤100,000
- 测试点 1-6 和 9 中,温度值不超过 100 100 100
- 测试点 7-8 和 10 中,温度值不超过 10 , 000 10,000 10,000。
思路
如图每次将差值加上不足的即可自动补齐
考虑负数情况两个ans取最大值即可
(https://img-blog.csdnimg.cn/5d4cb0b2964b4ddb8d7e926d3a3ff59b.png#pic_center)
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int n , ans1 , ans2;
int a[MAXN] , b[MAXN] , c[MAXN];
int main(){
// freopen("adjust.in" , "r" , stdin);
// freopen("adjust.out" , "w" , stdout);
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i];
for(int i = 1; i <= n; ++i)
cin >> b[i];
for(int i = 1; i <= n; ++i)
c[i] = a[i] - b[i];
for (int i = 1; i <= n; i++)
if(c[i] > c[i - 1])
ans1 += abs(c[i] - c[i - 1]);
else
ans2 += abs(c[i] - c[i - 1]);
cout << max(ans1 , ans2) << endl;
// fclose(stdin);
// fclose(stdout);
}
别人的代码(思路相似)
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int n , p[MAXN] , t[MAXN] , a[MAXN] , b[MAXN];
int main(){
// freopen("adjust.in" , "r" , stdin);
// freopen("adjust.out" , "w" , stdout);
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> p[i];
for(int i = 1;i <= n; ++i)
cin >> t[i];
for(int i = 1; i <= n; ++i){
int k = p[i] - t[i];
if(k >= 0) a[i]=k;
else b[i]=-k;
}
long long ans = 0;
for(int i = 1; i <= n; ++i){
if(a[i] > a[i - 1])
ans += a[i] - a[i - 1];
if(b[i] > b[i - 1])
ans += b[i] - b[i - 1];
}
cout << ans << endl;
// fclose(stdin);
// fclose(stdout);
return 0;
}