南昌网站建设利润/热门网站排名

南昌网站建设利润,热门网站排名,北京网站备案的地址,好的手机网站蓝桥杯 蓝桥杯题型分类语法基础艺术与篮球(日期问题)时间显示(时间问题)跑步计划(日期问题)偶串(字符)最长子序列(字符)字母数(进制转换)6个0&…

蓝桥杯

  • 蓝桥杯题型分类
    • 语法基础
      • 艺术与篮球(日期问题)
      • 时间显示(时间问题)
      • 跑步计划(日期问题)
      • 偶串(字符)
      • 最长子序列(字符)
      • 字母数(进制转换)
      • 6个0(进制转换)
      • 优秀的拆分(位运算)
      • 异或数列(位运算)
      • 幸运数字的个数(预计算)
    • 填空
      • 握手问题
      • 报数问题
    • 杂题
      • 游戏专家(零和博弈)
      • 大衣的异或回文对(回文判断)
      • 寻找至宝的奥秘(数学)
      • 小蓝的战斗计划
      • 公司名称(字符串)
      • 航班时间(字符串读取+方程式)
      • 蓝桥村的神秘信件(字符串)
      • 打开石门
      • 诺伊的神秘密码(字符串切割)
      • 超级的大串 (字符组合)
      • 食堂活动 (哈希字符)
      • 特殊日期
      • 高斯日记(日期差值)
      • 跑步锻炼(日期问题)
      • 回文日期
      • 特殊时间(枚举日期)
    • 二分
      • 123
    • 双指针
      • 小齐的奶牛配对挤奶计划
      • 卓儿探寻全球变暖

蓝桥杯题型分类

语法基础

艺术与篮球(日期问题)

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;map<char,int>myMap;
int basketball,calligraphy;//日期是否合法模板
int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(int date)
{int year=date/10000,month=date%10000/100,day=date%100;if(!month||month>=13||!day)return false;if(month!=2&&day>months[month])return false;if(month==2){int leap=(year%100!=0&&year%4==0)||year%400==0;if(day>28+leap)return false;}return true;
}int main() 
{// 插入数字与笔画数myMap['0'] = 13;myMap['1'] = 1;myMap['2'] = 2;myMap['3'] = 3;myMap['4'] = 5;myMap['5'] = 4;myMap['6'] = 4;myMap['7'] = 2;myMap['8'] = 2;myMap['9'] = 2;// 遍历日期范围,从2000年1月1日到2024年4月13日for(int i=20000101;i<=20240413;i++){if(check(i)){string s=to_string(i);int num=0;for(auto j:s){num+=myMap[j];}if(num>50){basketball++;}}}cout<<basketball;return 0;
}

时间显示(时间问题)

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
using ll = long long;int main() 
{ll x;cin >> x;// 计算小时、分钟、秒数ll hh = (x / 3600000) % 24;  // 小时数,取 24 小时制ll mm = (x / 60000) % 60;     // 分钟数,取 60 分钟ll ss = (x / 1000) % 60;      // 秒数,取 60 秒// 输出时间格式printf("%02lld:%02lld:%02lld", hh, mm, ss);return 0;
}

跑步计划(日期问题)

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  // 每个月的天数// 检查数字是否包含1
bool check(int x) {while (x) {if (x % 10 == 1) {return true;  // 如果数字中包含1,返回true}x /= 10;  // 去除最后一位}return false;  // 如果没有1,返回false
}int main() {int ans = 0;  // 总跑步的千米数int week = 6;  // 2023年1月1日是星期天,所以初始化为6(星期天)// 遍历每个月for (int i = 1; i <= 12; i++) {// 遍历每个月的每一天for (int j = 1; j <= months[i]; j++) {week = (week % 7) + 1;  // 更新星期几,确保在1到7之间循环(星期天为7)// 如果日期、月份或星期几包含1,跑5千米if (check(i) || check(j) || check(week)) {ans += 5;} else {ans += 1;  // 否则跑1千米}}}cout << ans;  // 输出小蓝总共跑的千米数return 0;
}

偶串(字符)

在这里插入图片描述

使用 Map 或者 unordered_map。
遍历字符串中的每个字符。对每个字符,检查它是否已经在你的数据结构中。如果是,增加它的计数。
#include <iostream>
#include <unordered_map>
using namespace std;int main() {string str;cin >> str;  // 输入字符串unordered_map<char, int> char_count;  // 用哈希表存储每个字符的出现次数// 遍历字符串并统计每个字符的出现次数for (char c : str) {char_count[c]++;}// 检查是否每个字符出现次数为偶数bool is_even = true;for (auto& pair : char_count) {if (pair.second % 2 != 0) {  // 如果出现次数是奇数is_even = false;break;}}// 输出结果if (is_even) {cout << "YES" << endl;} else {cout << "NO" << endl;}return 0;
}
创建一个大小为26的整数数组(假设为 cnt),用于存储每个小写字母的出现次数。数组的索引 
0−25 分别对应字母 a-z。
遍历字符串的每一个字符(假设为 c):
将字符 c 转为其 ASCII 值。
通过计算 c - 'a' 来得到一个从 0
0 到 25 的索引,这个索引对应于字符 c。
使用这个索引来增加 cnt 数组中对应元素的值。
遍历结束后,cnt 数组中的每个元素就存储了对应字母在字符串中的出现次数。
#include <iostream>
#include <vector>using namespace std;int main()
{string s;vector<int> cnt(26);cin >> s;for (auto c : s){cnt[c - 'a']++;}for (int i = 0; i < 26; ++i){if (cnt[i] % 2){cout << "NO" << '\n';return 0;}}cout << "YES" << '\n';return 0;
}

最长子序列(字符)

在这里插入图片描述

#include <iostream>
#include <string>
using namespace std;int main() {string s, t;int num = 0;cin >> s >> t;for (char ch : t) {// 查找当前字符ch在s中的位置size_t pos = s.find(ch);if (pos == string::npos) {// 如果找不到字符,直接输出已找到的匹配数并结束程序cout << num;return 0;} else {// 如果找到了字符,更新字符串s并增加计数num++;s = s.substr(pos + 1);  // 从pos+1开始截取s}}// 输出最终匹配的字符数cout << num;return 0;
}

字母数(进制转换)

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;using ll=long long;
int a[1000];
char ch[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };bool solve(int x)//十进制转换为16进制
{string ans;while(x){if(ch[x%16]>='A'){ans+=ch[x%16];x/=16;}else{return false;}}reverse(ans.begin(),ans.end());return true;
}
int main() 
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int i=2022;while(true){i++;if( solve(i)){cout<<i;return 0;}}return 0;
}

6个0(进制转换)

#include <bits/stdc++.h>
using namespace std;bool check(int x)
{// 检查最低的 5 位是否都为 0for(int i = 0; i < 5; i++){if(((x >> i) & 1) != 0) // 如果第 i 位不为 0,返回 false{return false;}}return true;
}int main() 
{int x = 2022; // 从 2022 开始查找while(true){x++; // 从 2023 开始检查if(check(x)) // 如果 x 的最低 5 位全为 0{cout << x;return 0;}}return 0;
}

优秀的拆分(位运算)

在这里插入图片描述

  • 输入输出样例
    示例 1
    输入

6

输出

4 2

示例 2
输入

7

输出

-1

7的二进制数为(0111),6的二进制数为(0110),可以发现7的二进制位的最低位(第0位)为1,值为
2 0 2^0 20 ,所以只要最低位为1,就不是优秀的拆分。我的从最高位开始遍历,只要第i位为1,我们就输出 1<<i ,即为 2 i 2^i 2i

#include <bits/stdc++.h>
using namespace std;int main() {int num;cin >> num;// 如果最低位为 1,输出 -1if (((num >> 0) & 1) == 1) {cout << -1 << endl;return 0;}// 从最高位开始遍历,检查每一位for (int i = 30; i >= 0; i--) {// 如果当前位为 1,输出 2^iif (((num >> i) & 1) == 1) {cout << (1 << i) << " ";}}return 0;
}

异或数列(位运算)

在这里插入图片描述
示例 1

输入
4
1 1
1 0
2 2 1
7 992438 1006399 781139 985280 4729 872779 563580

输出
1
0
1
1

解题思路

我们设在游戏结束后 Alice 的数变为 c,Bob 的数变为 d

我们先来解决平局的情况:

根据异或性质可得:若 c = d,则 c ⊕ d = 0

c ⊕ d = X1 ⊕ X2 ⊕ ⋯ ⊕ Xn,所以要使 c = d,当且仅当 X1 ⊕ X2 ⊕ ⋯ ⊕ Xn = 0

接下来定输赢:

我们将 c, d 转换成二进制数。对于二进制数的比较,我们是从高位往低位开始的。所以要使自己的数最大,就需要从高位开始。

设当前枚举到二进制的第 i 位。设 X1, X2, X3, ..., Xn 中一共有 cnt1 个数在该位的值为 1cnt2 个数在该位的值为 0。(cnt1 + cnt2 = n

结论一

如果 cnt1 为偶数,则 Alice 和 Bob 无法在该位分出胜负。

证明方法和上述平局情况相同。 或者也可以这么想:cnt1 为偶数,那么 Alice 和 Bob 要么都从这 cnt1 个数中分到偶数个,要么 Alice 和 Bob 都在这 cnt1 个数中分到奇数个;所以无论怎么分配,c, d 在该位的异或值都必然相同。

反之当 cnt1 为奇数时,必然能决出胜负。证明方法和上述类似,就不再给出。

那么 cnt1 为奇数时如何判断谁输谁赢呢?

我们先定义,对于当前第 i 位,如果能让自己的数值从 0 → 1,或者能让对手的数值从 1 → 0,则自己的胜率 +1;如果让自己的数值从 1 → 0,或者让对手的数值从 0 → 1,则自己的胜率 -1;如果既不改变自己的数值,也不改变对手的数值,则自己的胜率不变。显然,游戏结束时,胜率越高的一方获胜。

结论二

cnt1 为奇数,cnt2 = 0 时,先手必胜。

证明:

模拟一下可以发现先手后手走的每一步都必然是让自己胜率增加的一步。由于 cnt1 为奇数,所以先手可以比后手多走一步,所以先手的胜率必然会比后手高。

那么什么情况下必然会使自己的胜率减少呢?即当自己的数值为 1,且对手的数值为 0,且公共数列中只有 1 可以选取时。

结论三

谁的胜率率先减少,则谁必败。

证明: 由于一方胜率减少了,所以可得公共数列中只有 1 可以选取,没有 0 可以选取。

设胜率率先减少的 Alice,那么此时 AliceBob 的数值只有两种可能:

  1. Alice 的数值为 0Bob 的数值为 0
  2. Alice 的数值为 1Bob 的数值为 1

由于 AliceBob 的数值相同,所以公共序列中使用的 1 的个数必然为偶数,剩余的 1 的个数必然为奇数。且此时是 Bob 先手,根据结论二,Bob 必胜,Alice 必败,证明完毕。

那么谁的胜率会先减少的呢?

结论四

cnt1cnt2 为奇数时且 cnt1 > 1 时,先手的胜率会率先减少。

证明:cnt2 为奇数时,先手第一步只能选取 0 或是 1

  • 若先手先取 1 则后手取 0。此时先手的数值为 1,后手的数值为 0。为了不让自己的胜率降低,先手只能取 0,而后手也接着取 0。由于 0 个为奇数,所以先手将率先无法取 0,只能取 1,使得自己的胜率降低。
  • 若先手取 0 则后手也取 0。此时场面还是 1 的个数为奇数,0 的个数为奇数的情况。若先手率先取了 1,则就回到了上述的情况,先手必败。所以先手只能不断取 0,而后手也跟着不断取 0。最后先手取完 0,将剩余奇数个 1,回到了结论三的情况。由于此时到了后手的轮次,所以先手必败。

结论五

cnt1 = 1 时,先手必胜。

证明略。

根据上述五个结论,模拟一遍即可。

复杂度为 O(22 ∑ i=1 Tni)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N];signed main() {int T = 1;cin >> T;while(T--) {int n, sum = 0, ans = 0;cin >> n;// 读取输入并计算异或和for(int i = 1; i <= n; i++) {cin >> a[i];sum ^= a[i];}// 结论1:如果异或和为 0,则平局if (!sum) {cout << 0 << '\n';continue;}// 对每一位进行分析for (int j = 20; j >= 0; j--) {int one = 0, zero = 0;// 统计当前位上的1和0的数量for (int i = 1; i <= n; i++) {if (a[i] >> j & 1) one++;else zero++;}// 结论2 如果当前位有奇数个1,则确定胜负if (one & 1) {if (zero % 2 && one != 1) ans = -1;  //结论4 不满足条件,Bob 获胜else ans = 1;  // 满足条件,Alice 获胜break;}}cout << ans << '\n';  // 输出结果}return 0;
}

幸运数字的个数(预计算)

在这里插入图片描述

样例输入
6
1 10
1 16
1 17
10 100
100 1000
1000 10000

样例输出
10
15
16
11
13
14

说明
对于所有评测数据:

1 ≤ T ≤ 1 0 5 , 1 ≤ l i ≤ r i ≤ 1 0 12 。 1≤T≤10^5,1≤l_i ≤r_i≤10^{12} 。 1T105,1liri1012

要用到的思想是先“离线”预计算所有可能的幸运数字,再用二分查找快速计算每个查询区间内的幸运数字数量。具体做法如下:

先枚举所有“十六进制中由同一字符重复”的数字,排除超过 10^12 的值,并将这些数字存储到一个数组并排序;
对每次给定的范围 [l, r],使用二分查找定位区间上下界,从而快速统计落在该区间内的幸运数字个数。

#include <bits/stdc++.h>
using namespace std;static const long long MAX_VAL = 1000000000000LL; // 1e12// 预先生成所有在 [1, 1e12] 范围内 "十六进制由同一数字重复" 的幸运数字
// 注意:digit 取值范围是 [0..15],长度取值范围适当即可(1~16足够覆盖1e12)
vector<long long> generateLuckyNumbers() {vector<long long> luckyNums;// 十六进制最大可用字符:0~f (共16个)for (int digit = 0; digit < 16; ++digit) {for (int length = 1; length <= 16; ++length) {// 构建长度为 length 的重复字符// 例如若 digit = 12 (十六进制 c),length = 4,则是"cccc"// 然后转为十进制,判断是否 <= 1e12// digit 转成对应的16进制字符char hexDigit;if (digit < 10) {hexDigit = char(digit + '0');} else {hexDigit = char(digit - 10 + 'a');}// 构建重复串string hexStr(length, hexDigit);// 转成十进制// stoll(hexStr, nullptr, 16) 有可能超范围,用更安全方式// 这里用 64位整型计算long long num = 0;for (char c : hexStr) {// digitVal 可以用 c - '0' 或 c - 'a' + 10// 但我们已经知道是同一个字符int val;if (isdigit(c))val = c - '0';elseval = c - 'a' + 10;num = num * 16 + val;// 若已经超过范围就中断if (num > MAX_VAL) break;}if (num > 0 && num <= MAX_VAL) {luckyNums.push_back(num);}}}// 去重并排序sort(luckyNums.begin(), luckyNums.end());luckyNums.erase(unique(luckyNums.begin(), luckyNums.end()), luckyNums.end());return luckyNums;
}int main(){ios::sync_with_stdio(false);cin.tie(nullptr);// 预先生成所有可能的幸运数字static vector<long long> luckyNumbers = generateLuckyNumbers();int T;cin >> T;while (T--) {long long l, r;cin >> l >> r;// 在 luckyNumbers 中,用二分查找统计区间 [l, r] 内的元素个数auto leftIt = lower_bound(luckyNumbers.begin(), luckyNumbers.end(), l);auto rightIt = upper_bound(luckyNumbers.begin(), luckyNumbers.end(), r);cout << (rightIt - leftIt) << "\n";}return 0;
}

填空

握手问题

在这里插入图片描述
对于第一个人来说 除了自己以外要跟其他49人握手 所以第一个是49 ,对于第二个人来说 第一个人主动跟我握手了 有一次不算 所以第二个是48.。 以此类推 第43个人就是7 到了最后七个人呢 因为互相都没有握手 并且7个人都被前面的人握过手了 所以都是0

#include <iostream>
using namespace std;
int main(){int sum=0;for(int i=7;i<=49;i++) sum+=i;cout<<sum;return 0;
}

报数问题

在这里插入图片描述

1-10个: 20 24 40 48 60 72 80 96 100 12011-20个:140 144 160 168 180 192 200 216 220 24021-30个:260 264 280 288 300 312 320 336 340 36031-40个:380 384 400 408 420 432 440 456 460 480思路一:发现第10个数,第20个数,第30个数,第40个数......(每十个数为一轮)等等都是120的倍数,既然题目要求第202420242024个数,那我们不妨先求第202420242020个数,然后再往后再多求4个数就行。也就是202420242020/10*120=202429042904240,找它之后的四个能被2024整除的数,也就是2429042904288思路二:通过观察发现,第奇数位个数是20的倍数,第偶数位个数是24的倍数。所以第202420242024个数就是24的倍数,那我们直接除以2(判断是这个数是第几个24的倍数),然后再乘24就行。也就是202420242024÷2×24=2429042904288

杂题

游戏专家(零和博弈)

在这里插入图片描述

输入格式
一行一个字符串
s(1≤∣s∣≤1000)由小写英文字母组成。
样例输入
bazabyakslfd

样例输出
zbybzazazaza

分治思想(交替处理策略)先行者和后行者对应偶数和奇数
我们轮流让小蓝和小桥修改字符串,小蓝尽量将字符变成字典序最大的字母 z,小桥尽量将字符变成字典序最小的字母 a。

#include <bits/stdc++.h>
using namespace std;int main()
{string s;cin >> s;int n = s.size();// 轮流修改字符串for (int i = 0; i < n; i++){if (i % 2 == 0)  // 小蓝的回合,尽量使字典序最大{if (s[i] != 'z')  // 如果当前字符不是'z',则将其改为'z'{s[i] = 'z';}}else  // 小桥的回合,尽量使字典序最小{if (s[i] != 'a')  // 如果当前字符不是'a',则将其改为'a'{s[i] = 'a';}}}cout << s;  // 输出最终字符串return 0;
}

大衣的异或回文对(回文判断)

在这里插入图片描述

样例输入1
4
13 27 12 26

样例输出1
8

样例输入2
3
2 2 2

样例输出2
6

使用字符判断回文

// 判断整数 x 是否是回文
bool isPalindrome(int x) {string s = to_string(x);string rev_s(s.rbegin(), s.rend());return s == rev_s;
}

使用数字判断回文

#include <bits/stdc++.h>
using namespace std;
using ll = long long;const int N = 2e4 + 10;ll a[N];
ll ans;// 判断是否是回文数
bool hw(ll n) {ll sum = 0;ll k = n;while (n != 0) {sum = (sum * 10) + (n % 10);  // 反转数字n /= 10;}return sum == k;  // 如果反转的数字等于原数字,则为回文数
}int main() {ll n;cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];}// 遍历所有对 (i, j) 计算异或并判断是否是回文数for (int i = 1; i <= n; i++) {for (int j = i; j <= n; j++) {if (hw(a[i] ^ a[j])) {ans++;}}}cout << ans << endl;return 0;
}

寻找至宝的奥秘(数学)

在这里插入图片描述

最大公因数的基本概念
最大公因数(GCD)是指两个数的最大共有因子。比如,gcd(12, 15) = 3,因为 1215 都能被 3 整除,而没有比 3 更大的共同因子。

思路分析

  1. 最大公因数的性质

    • 假设我们有两个正整数 ab,如果它们的 GCD 很大,那么这两个数的因子也应该尽量重合。
    • 如果我们选取 a = nb = n / 2,那么它们的 GCD 通常会比较大。具体来说,gcd(n, n/2) 总是 n/2(这是因为 n/2n 的因子,并且它们共享 n/2 作为共同因子)。
  2. 为什么选择 nn / 2

    • 选择 nn / 2 作为候选

      • 如果我们选择两个数 a = nb = n / 2,这两个数之间的最大公因数是 n / 2。这是因为:
        • nn / 2 的倍数,nn / 2 的最大公因数就是 n / 2
      • 例如,当 n = 10 时,n = 10n / 2 = 5,这两个数的 GCD 是 5。
    • 为什么 n / 2 会是最大值

      • 当我们选择两个数时,我们希望它们的最大公因数尽可能大。n / 2n 最大的因子之一,所以选择 nn / 2 总是能得到最大的 GCD。
  3. 其他可能的组合

    • 如果选择 a = nb = n - 1,它们的最大公因数一般会较小,因为相邻的整数的 GCD 总是 1
    • 同理,其他的一些数对,如 a = nb = n - 2 等,都会比 n / 2n 的 GCD 小。

例子

  • 例子 1
    输入:n = 10

    • 我们选择 a = 10b = 10 / 2 = 5,计算 gcd(10, 5),结果是 5
    • 因为 105 的最大公因数是 5,这是最大的 GCD。
  • 例子 2
    输入:n = 12

    • 我们选择 a = 12b = 12 / 2 = 6,计算 gcd(12, 6),结果是 6
    • 因为 126 的最大公因数是 6,这是最大的 GCD。
#include <iostream>
using namespace std;int main() {int n;cin >> n;// 输出 n / 2 即可得到最大公因数cout << n / 2 << endl;return 0;
}

小蓝的战斗计划

在这里插入图片描述

  1. 优先尝试消灭需要 2 个单位时间的怪物:遍历排序后的所有时间段 b[i],如果 b[i] ≥ 2,就尽可能使用该时间段来消灭“需要 2 个单位时间”的怪物(min(cnt2, b[i]/2))。在此操作中,消灭多少头怪物,就从 cnt2 和 b[i] 各自对应的“数量”中减去相应数值。
  2. 然后尝试消灭需要 1 个单位时间的怪物:再次遍历同一个排序后的时间段数组,如果 b[i] ≥ 1,就用这个时间段去消灭尽量多的 cnt1 怪物(min(cnt1, b[i]))。
  3. 最后检查 cnt1 和 cnt2 是否都被消灭(即 cnt1 == 0 && cnt2 == 0)。若全部消灭则输出 “Y”,否则输出 “N”。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;int n, m;
int cnt1 = 0, cnt2 = 0;
int a[N], b[N];int main() {cin >> n >> m;// 输入怪物的战斗时间,并统计需要时间1和时间2的怪物数量for (int i = 1; i <= n; i++) {int x;cin >> x;if (x == 1) {cnt1++;} else {cnt2++;}}// 输入时间段的长度for (int i = 1; i <= m; i++) {cin >> b[i];}// 对时间段进行降序排序sort(b + 1, b + 1 + m, [](int u, int v) { return u > v; });// 优先使用时间段消灭需要时间2的怪物for (int i = 1; i <= m && cnt2 > 0; i++) {if (b[i] >= 2) {  // 如果时间段长度>=2,可以消灭一个需要时间2的怪物int x = min(cnt2, b[i] / 2);  // 计算能消灭多少个怪物cnt2 -= x;  // 更新需要消灭时间2的怪物数量}}// 使用剩余的时间段消灭需要时间1的怪物for (int i = 1; i <= m && cnt1 > 0; i++) {if (b[i] >= 1) {  // 如果时间段长度>=1,可以消灭一个需要时间1的怪物int x = min(cnt1, b[i]);  // 计算能消灭多少个怪物cnt1 -= x;  // 更新需要消灭时间1的怪物数量}}// 判断是否所有怪物都被消灭if (cnt1 == 0 && cnt2 == 0) {cout << "Y" << endl;} else {cout << "N" << endl;}return 0;
}

公司名称(字符串)

在这里插入图片描述

样例输入
5
7
Lqaaoin
7
Lanqiao
8
Lanqiaoo
2
ac
7
niLaqqa

样例输出
YES
YES
NO
NO
NO

#include <bits/stdc++.h>
using namespace std;int main() {string name = "Lanqiao";int t;cin >> t;while (t--) {int n;cin >> n;string s;cin >> s;if (name.length() == s.length()) {for (char j : name) {int pos = s.find(j);if (pos != string::npos) {s.erase(pos, 1); // 从pos开始删除一个字符}}if (s.empty()) cout << "YES" << endl;else cout << "NO" << endl;} else {cout << "NO" << endl;}}return 0;
}

航班时间(字符串读取+方程式)

传送门
在这里插入图片描述

输出描述
对于每一组数据输出一行一个时间 hh:mm:ss,表示飞行时间为 hh 小时 mm 分 ss 秒。
注意,当时间为一位数时,要补齐前导零。如三小时四分五秒应写 03:04:05。

输入输出样例
示例

输入
3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)

输出
04:09:05
12:10:39
14:22:05

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
int getTime(void)
{int h1,m1,s1,h2,m2,s2,d=0;scanf("%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);int time=d*24*3600+h2*3600+m2*60+s2-(h1*3600+m1*60+s1);return time;
}
int main()
{int t;scanf("%d",&t);for(int i = 0; i < t; i++){int time1=getTime();int time2=getTime();int t=(time1+time2)/2;printf("%02d:%02d:%02d\n", t/3600, t/60%60, t%60);}return 0;
}

也可以使用sscanf,关于具体用法,可见传送门

#include <bits/stdc++.h>
using namespace std;// get_time 函数用于计算时间差(单位为秒)
int get_time() 
{string line;getline(cin, line); // 读一行时间字符串// 如果时间字符串没有以 ")" 结尾,则添加 "(+0)"if (line.back() != ')')  line += " (+0)";// 定义起飞时间和到达时间的各个组件int h1, m1, s1, h2, m2, s2, day;// 解析时间字符串,提取小时、分钟、秒和天数sscanf(line.c_str(), "%d:%d:%d %d:%d:%d (+%d)", &h1, &m1, &s1, &h2, &m2, &s2, &day);// 将时间转为秒数,起飞时间和到达时间int S = h1 * 3600 + m1 * 60 + s1; // 起飞时间:转为秒int E = h2 * 3600 + m2 * 60 + s2; // 到达时间:转为秒// 返回时间差,考虑到天数影响return E - S + day * 24 * 3600;
}int main() 
{string line;getline(cin, line); // 读取第一行int n;// 解析第一行,获取组数 nsscanf(line.c_str(), "%d", &n);// 循环处理每组数据while (n--) {// 计算两次时间差的平均值int ans = (get_time() + get_time()) / 2;// 输出结果,格式化为时:分:秒printf("%02d:%02d:%02d\n", ans / 3600, ans / 60 % 60, ans % 60);}
}

蓝桥村的神秘信件(字符串)

在这里插入图片描述

#include <iostream>
#include <unordered_map>
using namespace std;int main() {int N;string S;cin >> N;cin >> S;// 用哈希表来统计每个字符的频率unordered_map<char, int> freq;// 统计字符频率for (int i = 0; i < N; i++) {freq[S[i]]++;}// 查找第一个只出现一次的字符for (int i = 0; i < N; i++) {if (freq[S[i]] == 1) {cout << S[i] << endl;return 0; // 找到第一个只出现一次的字符后,直接返回}}// 如果没有找到,只出现一次的字符cout << -1 << endl;return 0;
}

打开石门

传送门
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;int main(){string s; cin >> s;  // 读取输入字符串int a = 0, b = 0;  // 初始化两个计数器:a用于统计LL对数,b用于统计QQ对数// 遍历字符串,检查相邻的字符对for (int i = 1; i < s.size(); i++) {if (s[i-1] == 'L' && s[i] == 'L') a++;  // 如果是LL相邻,a加1if (s[i-1] == 'Q' && s[i] == 'Q') b++;  // 如果是QQ相邻,b加1}// 输出最终能缩短到的最小长度cout << s.size() - max(a, b);  // 减去最大合并次数,得到最小长度return 0;
}

诺伊的神秘密码(字符串切割)

传送门
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;// 左旋操作:将第一个字符移动到末尾
string left(string s)
{return s.substr(1, s.size() - 1) + s[0];
}// 右旋操作:将最后一个字符移动到开头
string right(string s)
{return s[s.size() - 1] + s.substr(0, s.size() - 1);
}int main()
{string s;cin >> s;  // 输入字符串 S// 分别计算左旋和右旋后的结果string lefts = left(s);string rights = right(s);// 判断左旋和右旋后的结果是否相同if (lefts == rights){cout << "YES";  // 如果相同,则输出 YES}else{cout << "NO";  // 如果不同,则输出 NO}return 0;
}

超级的大串 (字符组合)

传送门
在这里插入图片描述

假设我们正在处理字符串 str = "abz", 且我们正在处理第 1 个字符 'b'

  • 如果我们选择一个字符 'c' 或更大的字符来替代 'b',那么在 'b' 后面的位置(即位置 2)可以选择任意的字符,直到字符串的结尾。假设右边的部分是 'z',可以替换成 'a''b''c''z',所以右侧的字符部分可以有 26 种可能。

为什么要用 26 的幂:

  • 字符串的每个位置有 26 个可能的字符(从 'a''z')。
  • 对于当前字符,如果我们选择了一个字典序大于当前字符的字符,那么剩下的字符都可以是任意的(即它们有 26 种可能)。

例如:

  • 如果我们选择 'c' 代替 'b',那么 'z' 后面的字符可以是任何字母,因此可能的组合数就是 26
  • 如果字符串中还有更多字符,那么我们可以继续这样选择。

对应的代码:

for (int j = 0; j < str.size() - i - 1; j++) res = res * 26 % mod;
  • str.size() - i - 1:这表示当前字符右边的字符数,i 是当前字符的索引。所以我们知道在 str[i] 后面有 str.size() - i - 1 个字符需要考虑。

  • res = res * 26 % mod:表示对于每一个后续位置,都会有 26 种可能的选择。所以我们用 26 来乘上当前的结果 res,并且对 mod 取模,确保结果不会溢出。

#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const int MOD = 998244353;int n;
string s;
ll ans = 0;  // 结果变量需要初始化int main() 
{cin >> n >> s;// 从字符串的每个字符开始遍历for (int i = 0; i < s.size(); i++) {ll res = 1;// 计算当前字符 's[i]' 在字母表中的位置int t = s[i] - 'a' + 1;  // 字母 'a' 的位置是 1,'b' 是 2,以此类推if (t == 26) {continue;  // 如果当前字符是 'z',跳过,因为没有比 'z' 更大的字符} else {// 对于当前位置后面的字符,每个字符有 26 种可能for (int j = 0; j < s.size() - i - 1; j++) {res = res * 26 % MOD;  // 计算后续字符的所有组合}// 计算比当前字符大的字符数res = res * (26 - t) % MOD;// 累加结果ans = (ans + res) % MOD;}}// 输出结果并对 998244353 取模cout << ans << endl;return 0;
}

食堂活动 (哈希字符)

传送门

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;// 用数组或 map 存储每种菜的价格// 字符是小写字母,所以我们可以用 char -> int 下标vector<long long> price(26, 0);for(int i = 0; i < n; i++){char c;long long p;cin >> c >> p;price[c - 'a'] = p;}// 读取点餐字符串string order;cin >> order;// 统计每种菜的点餐数量vector<long long> count(26, 0);for(char c : order){count[c - 'a']++;}// 计算总价// 活动:每点两份同种菜,就送一份同种菜,即3份只需付2份钱long long ans = 0;for(int i = 0; i < 26; i++){if(count[i] > 0 && price[i] > 0){long long x = count[i];long long fullSets = x / 3;         // 每3份只付2份钱long long remainder = x % 3;        long long costForDish = price[i] * (2LL * fullSets + remainder);ans += costForDish;}}cout << ans << "\n";return 0;
}

特殊日期

在这里插入图片描述

#include <iostream>
using namespace std;long long months[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool check(long long year)
{return (year%4==0&&year%100!=0)||year%400==0;
}
long long ans;
int main()
{for(int i=2000;i<2000000;i++){// 判断是否为闰年,并更新2月天数if(check(i)){months[2]=29;}else{months[2]=28;}for(int j=1;j<=12;j++) {if(i%j==0)  // 如果年份是该月份的倍数{for(int k=1;k<=months[j];k++)// 遍历该月的每一天{if(i%k==0) // 如果年份是该天数的倍数{ans++;}  }}}}ans++;// 2000000.1.1 不要忘记这个日期cout<<ans;return 0;
}

高斯日记(日期差值)

传送门
在这里插入图片描述

#include <iostream>
using namespace std;int months[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 判断是否为闰年
bool check(int year) {return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}int main() {int d = 8113 - 5343 - 16;  // 天数差int year = 1792, month, day;// 逐年递减,找到目标日期所在的年份while (d > 365) {d -= (365 + check(year));  // 减去每年天数,闰年则为366天year++;}// 判断目标年份是否是闰年,更新2月天数if (check(year)) {months[2] = 29;  // 闰年2月29天} else {months[2] = 28;  // 非闰年2月28天}// 逐月递减,找到目标月份和日期for (month = 1; d > months[month]; month++) {d -= months[month];  // 减去当前月的天数}day = d;  // 剩余的天数就是目标日期// 输出结果,确保格式为 yyyy-mm-ddprintf("%04d-%02d-%02d", year, month, day);return 0;
}

跑步锻炼(日期问题)

传送门
在这里插入图片描述

我们用 (sum + 6) % 7 来计算当前日期是星期几。为什么要加6呢?因为我们假设 2000年1月1日 是星期六,所以要调整到星期六作为起点。

#include <iostream>
using namespace std;int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};// check函数用于验证日期是否合法
bool check(int date)
{int year = date / 10000;        // 提取年份int month = date % 10000 / 100; // 提取月份int day = date % 100;           // 提取日期if (!month || month > 12 || !day) return false;if (month != 2 && day > months[month]) return false;if (month == 2){int leap = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);if (day > 28 + leap) return false;}/return true;
}int main()
{int ans = 0;   // 记录符合条件的日期数int sum = 0;   // 记录当前日期的星期几(从2000年1月1日开始)// 从2000年1月1日到2020年10月1日逐日检查for (int i = 20000101; i <= 20201001; i++){// 检查当前日期是否有效if (check(i)){ans++; // 如果是有效日期,增加答案计数int month = i % 10000 / 100; // 提取当前日期的月份int day = i % 100;           // 提取当前日期的日期// 如果是1号或者当前是星期一,增加答案计数if (day == 1 || (sum + 6) % 7 == 1){ans++; // 1号或者星期一时,计数加1}sum++; // 增加天数,更新星期几}}// 输出符合条件的日期数cout << ans;return 0;
}

回文日期

传送门
在这里插入图片描述

#include <iostream>
using namespace std;int month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// check函数用于判断日期是否合法
bool check(int n)
{// 分解年份、月份和日期int y = n / 10000;       int m = n % 10000 / 100;  int d = n % 100;          if (!m || !d || m >= 13) return false;if (m != 2 && d > month[m]) return false;if (m == 2){int leap = y % 400 == 0 || (y % 4 == 0 && y % 100 != 0);  if (d > 28 + leap) return false;  }return true;
}// check_abab函数用于检查日期是否符合"abab"格式
bool check_abab(int n)
{int a = n / 10000000;       // 提取第一个数字int b = n / 1000000 % 10;   // 提取第二个数字int c = n / 100000 % 10;    // 提取第三个数字int d = n / 10000 % 10;     // 提取第四个数字// 检查是否符合"abab"格式且a与b不相等if (a == c && b == d && a != b) return true;return false;
}int main()
{int n;cin >> n;  // 输入日期(格式为YYYYMMDD)int flag = 1;  // 用于标记是否已找到满足条件的日期// 从输入日期的年份开始逐年遍历for (int i = n / 10000; i <= 10000; i++){int date = i, x = i;// 构造出该年份的“abab”格式日期for (int j = 0; j < 4; j++){date = date * 10 + x % 10;  // 将当前年份的最后一个数字逐个加到日期中x /= 10;  // 去除最后一位数字}// 如果构造的日期有效,且大于输入日期,并且flag为1,则输出该日期if (check(date) && flag && date > n){cout << date << endl;flag = 0;  // 找到第一个符合条件的日期后,设flag为0,防止再次输出}// 如果构造的日期有效,并且符合"abab"格式,且大于输入日期,则输出并结束程序if (check(date) && check_abab(date) && date > n){cout << date;return 0;  }}return 0;  
}

特殊时间(枚举日期)

传送门
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;// 定义每个月所包含的天数(下标 0 未用)
int day_per_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};/*** @brief 检查传入的四位数 D(形如 MMDD)是否是一个合法日期* @param D 整数表示月日,如 0229、1231* @return 若是有效的月/日则返回 true,否则返回 false*/
bool check_D(int D){// 月份放在高两位int month = D / 100;// 天数放在低两位int day = D % 100;// 月份合法区间为 [1, 12]if(month < 1 || month > 12) return false;// 日数合法区间根据当月天数判定if(day < 1 || day > day_per_month[month]) return false;return true;
}/*** @brief 检查传入的四位数 H(形如 HHMM)是否是一个合法时间* @param H 整数表示小时分钟,如 0020、2359* @return 若是有效的小时/分钟则返回 true,否则返回 false*/
bool check_H(int H){// 小时放在高两位int h = H / 100;// 分钟放在低两位int m = H % 100;// 小时合法区间为 [0, 23]if(h < 0 || h > 23) return false;// 分钟合法区间为 [0, 59]if(m < 0 || m > 59) return false;return true;
}/*** @brief 主函数:通过枚举方式,统计由两个不同数字 (a, b) 组合成*  “3个相同 + 1个不同” 的4位数(用于表示年份、月日、时分)的有效组合*/
int main(){int ans = 0; // 统计符合要求的时间个数// 外层循环枚举第一个数字 afor(int a = 0; a <= 9; a++){// 内层循环枚举第二个数字 b,确保 a 与 b 不同for(int b = 0; b <= 9; b++){if(a != b){// 年份写成 4 位时全部使用 a,因此年份可以看作 aaaa// 程序中将其视作 "有 4 种情况"(N_Y=4),只是为了乘法计算便捷int N_Y = 4;  // 在本题理解为“年份 aaaa”时的简单做法int N_D = 0;  // 用来统计"3a + 1b" 所构造的四位数在日期上的合法个数int N_H = 0;  // 用来统计"3a + 1b" 所构造的四位数在时刻上的合法个数// 先把数组 A 初始化为 [a, a, a, a]int A[4] = {a, a, a, a};// 通过把 b 放在 4 个位置之一,枚举出 4 种排列:aaab, aaba, abaa, baaafor(int i = 0; i < 4; i++){A[i] = b;  // 将 b 放在第 i 个位置int number = 0;// 将 A[0..3] 拼接成一个四位数for(int j = 0; j < 4; j++){number = number * 10 + A[j];}// 检查该四位数是否能表示一个合法的 日期(月日)N_D += check_D(number);// 检查该四位数是否能表示一个合法的 时刻(小时分钟)N_H += check_H(number);A[i] = a; // 恢复现场,继续处理下一个位置}// ans += 年份的 4 种可能 * 合法日期数 * 合法时刻数ans += N_Y * N_D * N_H;}}}// 输出结果cout << ans << endl;return 0;
}

二分

123

传送门

在这里插入图片描述
在这里插入图片描述

1. 小区间的构成

假设数列的构成是如下形式:

  • 第 1 个区间包含 1 个元素(1)。
  • 第 2 个区间包含 2 个元素(1 2)。
  • 第 3 个区间包含 3 个元素(1 2 3)。
  • 第 4 个区间包含 4 个元素(1 2 3 4)。

i 个小区间包含 i 个元素。我们将这些小区间连起来形成整个数列。

2. 数组 a[j] 的定义

数组 a[j] 表示前 j 个小区间的总元素数,同时也能表示每个小区间的和。例如:

  • a[1] = 1 (表示前 1 个小区间有 1 个元素)
  • a[2] = 1 + 2 = 3 (表示前 2 个小区间共有 3 个元素)
  • a[3] = 1 + 2 + 3 = 6 (表示前 3 个小区间共有 6 个元素)
  • a[4] = 1 + 2 + 3 + 4 = 10 (表示前 4 个小区间共有 10 个元素)

注意,数组 a[j] 是单调递增的,因为每个小区间的元素个数都在增加。

关键点:k = i - a[j]

  • 数列中的位置 i 是在第 j+1 个区间中的某个元素。
  • j 个区间包含了 a[j] 个元素,也就是说,第 j+1 个区间的第一个元素出现在位置 a[j] + 1

因此,位置 i 在第 j+1 个区间的具体位置是:

  • j+1 个区间的第 k 个元素k 就是位置 i 相对于第 j+1 个区间开始位置的偏移量。

由于前 j 个区间包含了 a[j] 个元素,第 j+1 个区间从位置 a[j] + 1 开始。所以位置 i 在第 j+1 个区间中的具体位置是:

k = i - a[j]

#include <iostream>
using namespace std;
using ll=long long;
const int N=1414215;ll a[N],s[N];ll persum(ll i)
{ll l=0,r=N;while(l<r){ll mid=(l+r+1)>>1;if(a[mid]<i)l=mid;else r=mid-1;}return  s[l]+a[i-a[l]];
}
int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);for(int i=1;i<N;i++){a[i]=a[i-1]+i;s[i]=s[i-1]+a[i];}int t;cin>>t;while(t--){ll l,r;cin>>l>>r;cout<<persum(r)-persum(l-1)<<endl;}return 0;
}

双指针

小齐的奶牛配对挤奶计划

在这里插入图片描述

样例输入
3
1 8
2 5
1 2

样例输出
10

评测数据规模
1 ≤ M ≤ 1 , 000 , 000 , 000 , M 为偶数, 1 ≤ N ≤ 100 , 000 1≤M≤1,000,000,000,M 为偶数,1≤N≤100,000 1M1,000,000,000M为偶数,1N100,000

#include <bits/stdc++.h>
using namespace std;/*问题描述:给定若干组输入 (x, y),表示有 x 头奶牛,其挤奶产量为 y。这些 input 的 x 之和为 M(总奶牛数,且 M 为偶数)。将所有 M 头奶牛分成 M/2 对,并行挤奶时的总耗时,取决于所有配对 (A, B) 的挤奶时间 A+B 的最大值。目标是找到所有可能配对中,使 max(A+B) 最小的方案,并输出这个值。解决思路(双指针):1. 将每种产量 y 与其数量 x 记录下来,并按照 y 升序排序。2. 设置两端指针:left 指向最小产量,right 指向最大产量。3. 每次取尽可能多的奶牛对,数量为 min(左侧剩余奶牛数, 右侧剩余奶牛数)。4. 该批次配对的时间为 left 产量 + right 产量,用其更新全局最大值。5. 逐步减少两侧数量并移动指针,直至全部奶牛被配对完成。时间复杂度主要在对产量排序上,为 O(N log N),其中 N 最多为 100000(不按单头奶牛数量计)。
*/int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int N;cin >> N;// 记录 (y, x)vector<pair<long long, long long>> cows;cows.reserve(N);long long totalCount = 0; // 用于计算奶牛总数 Mfor (int i = 0; i < N; ++i) {long long x, y;cin >> x >> y;cows.push_back({y, x});totalCount += x;}// 按产量升序排序sort(cows.begin(), cows.end(), [](auto &a, auto &b){return a.first < b.first;});// 双指针:l 指向产量最小,r 指向产量最大int l = 0, r = (int)cows.size() - 1;long long res = 0;while (l <= r) {if (l == r) {// 剩余都在同一个产量上// 这时必然剩余的奶牛数为偶数,可以两两配对// 配对时间为 2 * cows[l].first// 但实际只需要一次就能给出最终答案res = max(res, 2LL * cows[l].first);break;}// 本轮可以配对的奶牛数long long num = min(cows[l].second, cows[r].second);// 对应配对时间long long sumTime = cows[l].first + cows[r].first;res = max(res, sumTime);// 扣除配对过的奶牛数cows[l].second -= num;cows[r].second -= num;// 如果左侧产量用完,则左指针右移if (cows[l].second == 0) {++l;}// 如果右侧产量用完,则右指针左移if (cows[r].second == 0) {--r;}}cout << res << "\n";return 0;
}

卓儿探寻全球变暖

在这里插入图片描述

样例输入
5 3
1 3 5 1 3
0 2 4

样例输出
1 2 1

1 ≤ n , d ≤ 1 0 5 , 1 ≤ h i ≤ 1 0 9 1≤n,d≤10^5,1≤h_i≤10^9 1n,d105,1hi109

暴力做法
变量含义:
• n 表示大楼数量,d 表示要查询的天数。
• 数组 h 存储每栋大楼的高度,数组 t 存储每个查询日对应的海平面高度。
• 布尔数组 st 标记某天是否“未被淹没”(true 为未淹没)。

对每个查询日的处理:
(1) 将大楼中高 <= 当前海平面的全部标记为 false(表示已淹没)。
(2) 随后扫描所有大楼,累积计算未淹没大楼所形成的连续“区域”数量:

  • 如果遇到一段连续的 true(未淹没大楼),则算作一个区域;
  • 当连续的 true 被一个 false(淹没大楼)打断时,再出现下一段 true 时,就会有一个新的区域。
    (3) 将最终区域数输出。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;// h[] 用于存储每栋大楼的高度
// t[] 用于存储不同查询日的海平面高度
// st[] 用于标记某栋大楼今日是否仍未被淹没
vector<int> h(N);
vector<int> t(N);
bool st[N];int main() {int n, d;// 输入 n(大楼数量)和 d(查询天数)cin >> n >> d;// 读取大楼高度for (int i = 1; i <= n; i++) {cin >> h[i];}// 读取查询海平面天数数组for (int i = 1; i <= d; i++) {cin >> t[i];}// 将 st[] 初始化为 true,表示初始默认所有大楼都未被淹没memset(st, true, sizeof(st));// 对每个查询天数分别进行处理int region = 0;  // 表示当前查询日下,未淹没大楼所形成的区域数量for (int i = 1; i <= d; i++) {int day = t[i];    // 当前海平面高度region = 0;        // 每次查询前重置区域数bool flag = false; // 标记是否在扫描大楼时已经遇到一个“连续未淹没区域”// 1) 更新 st[j]: 若大楼高度 <= 当前海平面,则标记为已被淹没 (false)for (int j = 1; j <= n; j++) {if (h[j] <= day) {st[j] = false;}}// 2) 统计当前未淹没楼形成的连续区域数for (int j = 1; j <= n; j++) {if (st[j]) {// 如果此楼未淹没并且尚未记录一个新区域,则区域数加一if (!flag) {region++;flag = true;  // 进入新区域}} else {// 如果此楼已被淹没,则结束之前的未淹没区域标记flag = false;}}// 输出当日的区域数cout << region << " ";}return 0;
}

双指针+排序

  1. 首先,将所有大楼 (高度, 下标) 按高度从小到大排序,便于后续根据海平面高度逐步淹没。
  2. 随后,有一个双指针循环:当海平面上升到 t[i] 时,就把所有高度 ≤ t[i] 的大楼“标记”为淹没(分别存储到 drown[i] 列表)。
  3. 利用一个布尔数组 st[] 来标记下标为 x 的大楼是否已被淹没;给 0 与 n+1 这两个“边界”强制设为已淹没状态(true),方便识别某大楼左右是否都是淹没状态。
  4. 遍历 drown[i],对于每一个新淹没的大楼 x:
    • 若 x 左右均尚未淹没,则此次淹没会把原来的一个区域分割成两个,因此区域计数 ans 增加 1。
    • 若 x 左右均已经淹没,则原先的两个淹没区在 x 处“连接”为一个区,区域计数 ans 减少 1。
    • 最后将 x 标记为已淹没。
  5. 每次处理完后,输出当前 ans 值,即此刻剩余未淹没大楼的整体区域数量。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;bool st[N];
int main() {int n, d;cin >> n >> d;vector<pair<int,int>>h(n+1);// h[]数组存储(大楼高度, 其原始下标),下标从1开始使用for (int i = 1; i <= n; i++) {cin>>h[i].first;// 读入大楼高度h[i].second=i; // 存储对应的原始位置}// t[]数组存储每个查询的海平面高度(总共有d次查询)vector<int> t(d);for (int i = 0; i < d; i++) {cin >> t[i]; // 读入第i次查询的海平面高度}// 将 h 中的大楼数据按高度升序进行排序sort(h.begin() + 1, h.end());// drown[i]存储在第i次查询中「新被淹没」的大楼下标vector<vector<int>>drown(d);// 双指针:i遍历查询,j遍历大楼列表// 若 h[j+1].first <= t[i] => 说明该楼在第i次查询时已经被淹没// 则记录其位置到drown[i]中表示本轮新增被淹没的楼for (int i = 0, j = 0; i < d; i++) {while (j + 1 <= n && h[j + 1].first <= t[i]) {j++;drown[i].emplace_back(h[j].second);}}// st[x]用于标记下标为x的楼是否已被淹没// 在边界0和n+1处设置为true,方便判断左右是否淹没st[0] = true;      // 边界视为已淹没st[n + 1] = true;  // 边界视为已淹没int ans = 1;        // 当前未淹没的大楼形成的区域数,初始设为1// 遍历每个查询,将在该日新增被淹没的楼进行处理for(auto &u:drown){// u中存储了本次查询“刚好在海平面下”的大楼索引for(auto x:u){// 情况1:若左右都未被淹,则淹没x会把一个连续区域分成两部分 => 区域数 +1if(!st[x-1]&&!st[x+1]){ans+=1;}// 情况2:若左右都已淹,则淹没x会将两个淹没区“连接”,相当于减少一个区域 => 区域数 -1if (st[x - 1] && st[x + 1]) {ans -= 1;}st[x]=true;}cout<<ans<<" ";}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot框架总结(超级详细)

前言 本篇文章包含Springboot配置文件解释、热部署、自动装配原理源码级剖析、内嵌tomcat源码级剖析、缓存深入、多环境部署等等&#xff0c;如果能耐心看完&#xff0c;想必会有不少收获。 一、Spring Boot基础应用 Spring Boot特征 概念&#xff1a; 约定优于配置&#…

AI开发利器:miniforge3无感平替Anaconda3

相信有和我遭遇一样的同学吧&#xff0c;之前装了anaconda用的挺好的&#xff08;可以参考AI开发利器&#xff1a;Anaconda&#xff09;&#xff0c;但是考虑到有可能收到软件侵权的律师函的风险&#xff0c;还是果断找个替代品把anaconda卸载掉。miniforge就是在这样的背景下发…

用 Vue 3.5 TypeScript 做了一个日期选择器(改进版)

上一篇 已经实现了一个日期选择器&#xff0c;只不过是模态窗的形式&#xff0c;这个版本改为文本框弹出&#xff0c;点击空白处可关闭日历 代码也增加了不少 <template><div><!-- 添加文本框 --><div class"date-picker-input-wrapper">&l…

【爬虫】开篇词

一、网络爬虫概述 二、网络爬虫的应用场景 三、爬虫的痛点 四、需要掌握哪些技术&#xff1f; 在这个信息爆炸的时代&#xff0c;如何高效地获取和处理海量数据成为一项核心技能。无论是数据分析、商业情报、学术研究&#xff0c;还是人工智能训练&#xff0c;网络爬虫&…

文字转语音chat-tts-ui

去年已经使用过chattts了&#xff0c;但是昨晚想用的时候却记怎么打开了&#xff0c;找了一下以前的笔记 MacOS 下源码部署chat-tts-ui 配置好 python3.9-3.11 环境,安装git &#xff0c;执行命令 brew install libsndfile git python3.10 继续执行 brew install ffmpeg ​ …

基于SpringBoot+Vue的瑜伽课体验课预约系统【附源码】

基于SpringBootVue的瑜伽课体验课预约系统 一、系统技术说明二、运行说明三、系统的演示四、系统的核心代码演示 一、系统技术说明 框架&#xff1a;SpringbootVue 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软…

sparkTTS window 安装

SparkTTS 的简介 Spark-TTS是一种基于SpardAudio团队提出的 BiCodec 构建的新系统&#xff0c;BiCodec 是一种单流语音编解码器&#xff0c;可将语音策略性地分解为两种互补的标记类型&#xff1a;用于语言内容的低比特率语义标记和用于说话者特定属性的固定长度全局标记。这种…

ApoorvCTF Rust语言逆向实战

上周参加了国外的比赛&#xff0c;名称叫&#xff1a;ApoorvCTF 看一下老外的比赛跟我们有什么不同&#xff0c;然后我根据国内比赛对比发现&#xff0c;他们考点还是很有意思的&#xff0c;反正都是逆向&#xff0c;哈哈哈 Rusty Vault 题目描述&#xff1a; In the heart…

Git和GitHub基础教学

文章目录 1. 前言2. 历史3. 下载安装Git3.1 下载Git3.2 安装Git3.3 验证安装是否成功 4. 配置Git5. Git基础使用5.1 通过Git Bash使用5.1.1 创建一个新的仓库。5.1.1.1 克隆别人的仓库5.1.1.2 自己创建一个本地仓库 5.1.2 管理存档 5.2 通过Visual Studio Code使用 6. Git完成远…

MySQL中like模糊查询如何优化?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL中like模糊查询如何优化?】面试题。希望对大家有帮助&#xff1b; MySQL中like模糊查询如何优化? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中&#xff0c;LIKE 模糊查询虽然非常常见&#xff0c;…

⭐LeetCode(数学分类) 2. 两数相加——暴力与优化⭐

⭐LeetCode(数学分类) 2. 两数相加——暴力与优化⭐ 提示&#xff1a; 每个链表中的节点数在范围 [1, 100] 内 0 < Node.val < 9 题目数据保证列表表示的数字不含前导零 题解&#xff1a; 暴力与优化&#xff0c;暴力即转换为十进制解题&#xff0c;优化即直接在链表上进…

①Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网

Modbus TCP转Modbus RTU/ASCII网关同步采集无需编程高速轻松组网https://item.taobao.com/item.htm?ftt&id784749793551 MODBUS TCP 通信单元 MODBUS TCP 转 RS485 MS-A1-50X1 系列概述 MS-A1-50X1 系列概述 MS-A1-50X1系列作为MODBUS TCP通信的服务器进行动作。可通…

C/C++蓝桥杯算法真题打卡(Day3)

一、P8598 [蓝桥杯 2013 省 AB] 错误票据 - 洛谷 算法代码&#xff1a; #include<bits/stdc.h> using namespace std;int main() {int N;cin >> N; // 读取数据行数unordered_map<int, int> idCount; // 用于统计每个ID出现的次数vector<int> ids; …

<建模软件安装教程1>Blender4.2系列

Blender4.2安装教程 0注意&#xff1a;Windows环境下安装 第一步&#xff0c;百度网盘提取安装包。百度网盘链接&#xff1a;通过网盘分享的文件&#xff1a;blender.zip 链接: https://pan.baidu.com/s/1OG0jMMtN0qWDSQ6z_rE-9w 提取码: 0309 --来自百度网盘超级会员v3的分…

C语言八股---预处理,编译,汇编与链接篇

前言 从多个.c文件到达一个可执行文件的四步:   预处理–>编译–>汇编–>链接 预处理 预处理过程就是预处理器处理这些预处理指令(要不然编译器完全不认识),最终会生成 main.i的文件 主要做的事情有如下几点: 展开头文件展开宏条件编译删除注释添加行号等信息保留…

用Deepseek写一个 HTML 和 JavaScript 实现一个简单的飞机游戏

大家好&#xff01;今天我将分享如何使用 HTML 和 JavaScript 编写一个简单的飞机游戏。这个游戏的核心功能包括&#xff1a;控制飞机移动、发射子弹、敌机生成、碰撞检测和得分统计。代码简洁易懂&#xff0c;适合初学者学习和实践。 游戏功能概述 玩家控制&#xff1a;使用键…

面向高质量视频生成的扩散模型方法-算法、架构与实现【附核心代码】

目录 算法原理 架构 代码示例 算法原理 正向扩散过程&#xff1a;从真实的视频数据开始&#xff0c;逐步向其中添加噪声&#xff0c;随着时间步 t 的增加&#xff0c;噪声添加得越来越多&#xff0c;最终将原始视频数据变成纯噪声。数学上&#xff0c;t 时刻的视频数据与 t…

游戏引擎学习第149天

今日回顾与计划 在今天的直播中&#xff0c;我们将继续进行游戏的开发工作&#xff0c;目标是完成资产文件&#xff08;pack file&#xff09;的测试版本。目前&#xff0c;游戏的资源&#xff08;如位图和声音文件&#xff09;是直接从磁盘加载的&#xff0c;而我们正在将其转…

ForceMimic:以力为中心的模仿学习,采用力运动捕捉系统进行接触丰富的操作

25年3月来自上海交大卢策吾教授团队的论文“ForceMimic: Force-Centric Imitation Learning with Force-Motion Capture System for Contact-Rich Manipulation”。 在大多数接触丰富的操作任务中&#xff0c;人类会将随时间变化的力施加到目标物体上&#xff0c;以补偿视觉引…

【愚公系列】《Python网络爬虫从入门到精通》045-Charles的SSL证书的安装

标题详情作者简介愚公搬代码头衔华为云特约编辑&#xff0c;华为云云享专家&#xff0c;华为开发者专家&#xff0c;华为产品云测专家&#xff0c;CSDN博客专家&#xff0c;CSDN商业化专家&#xff0c;阿里云专家博主&#xff0c;阿里云签约作者&#xff0c;腾讯云优秀博主&…