A
考察点:格式化输入
签到题,直接输入输出即可。
时间复杂度:
ACcode
#include <iostream>
#define endl '\n'
using namespace std;
int main(){
int a, b, c;
scanf("%d-%d-%d", &a, &b, &c);
cout << a << ' ' << b << ' ' << c << endl;
return 0;
}
B
考察点:for循环暴力、字符串
循环暴力遍历所有的四个字符,如果能拼成"ming"就给答案+1,输出答案即可。
时间复杂度:
ACcode
#include <iostream>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
string s;
cin >> s;
int n = s.size();
int cnt = 0;
for(int i = 0; i < n - 3; i++){
for(int j = i + 1; j < n - 2; j++){
for(int k = j + 1; k < n - 1; k++){
for(int l = k + 1; l < n; l++){
if(s[i] == 'm' && s[j] == 'i' && s[k] == 'n' && s[l] == 'g'){
cnt++;
}
}
}
}
}
cout << cnt << endl;
return 0;
}
C
考察点:构造、思维、贪心
单调不增包含单调递减,只需将这个排列逆序输出,就能保证,符合题目条件。
时间复杂度:
ACcode
#include <iostream>
#define endl '\n'
using namespace std;
void solve(){
int n;
cin >> n;
for(int i = n; i > 0; i--) cout << i << ' ';
cout << endl;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--){
solve();
}
return 0;
}
D
考察点:排序、贪心
任取一个长度为的子序列就是在数组中任取
个数,想让和最大,只需贪心取最大的
个数,将数组排序后输出后
个数的和即可。
时间复杂度:
ACcode
#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;
int a[1000005];
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
long long sum = 0;
for(int i = 0; i < n; i++){
cin >> a[i];
}
sort(a, a + n);
for(int i = n; i >= n - k; i--) sum += a[i];
cout << sum << endl;
return 0;
}
E
考察点:前缀和
取长度为的子数组就是在数组中取一段长度为
的区间,遍历所有可能的区间左端点(右端点),用前缀和来计算区间和,每次更新最大区间和即可。
时间复杂度:
ACcode
#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;
int a[1000005];
long long pre[1000005];
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
long long res = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
}
for(int i = 0; i <= n - k; i++){
res = max(res, pre[i + k] - pre[i]);
}
cout << res << endl;
return 0;
}
F
考察点:结构体、sort
用一个三个元素的结构体表示每道菜,创建一个结构体数组,输入道菜的信息,然后按题意要求(按美味值从高到低排,如果美味值相同,按饱腹值从低到高排)写排序函数,
排序,然后遍历一遍数组,看饱腹值能不能吃当前食物,能吃就把价值加到答案即可。
注意:如果一道菜吃不下就看小明想吃的下一道,而不是直接不吃,所以这个时候不能直接将循环,一定要把数组遍历完。
时间复杂度:
ACcode
#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;
struct Food{
int a, b, c;
}p[200005];
bool cmp(Food a, Food b){
if(a.a == b.a) return a.b < b.b;
return a.a > b.a;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m;
cin >> n >>m;
for(int i = 0; i < n; i++){
cin >> p[i].a >> p[i].b >> p[i].c;
}
sort(p, p + n, cmp);
int sum = 0;
long long res = 0;
for(int i = 0; i < n; i++){
if(sum + p[i].b <= m){
sum += p[i].b;
res += p[i].c;
}
}
cout << res << endl;
return 0;
}
G
考察点:二分答案
一眼二分答案,答案的右边界初步计算会爆
,那就在
的范围(
~
)搜,
函数就是遍历每个打包员,看其在
分钟能打包多少个快递(
),看所有的打包员总共能打包的快递数是否
即可,如果满足条件就继续向左找(
),看看还有没有分钟数更少的方案。
时间复杂度:
ACcode
#include <iostream>
#include <algorithm>
#include <cmath>
#define endl '\n'
using namespace std;
int n, m;
int a[200005];
bool check(long long x){
long long sum = 0;
for(int i = 0; i < n; i++){
sum += sqrt(x / a[i]);
if(sum >= m) return true;
}
return false;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m;
for(int i = 0; i < n; i++){
cin >> a[i];
}
long long l = 0, r = 1e18;
while(l < r){
long long mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
H
考察点:数学、贪心
这题的数字可以用整形输入,然后用循环把数的一位一位取出来,存到
或数组里,再翻转,但比较麻烦,其实可以直接用字符串表示这个数。从右到左找到第一个
的地方,如果找不到就直接输出
,把这个位置存下来。从这个位置往后遍历,把最后一个比
大的数字和
交换,然后把后面所有的数升序排列,这个时候的数就是题里的答案。
时间复杂度:
ACcode1
#include <iostream>
#include <algorithm>
#include <cmath>
#define endl '\n'
using namespace std;
void solve(){
string a;
cin >> a;
int n = a.size();
int pos1 = -1, pos2 = -1;
for(int i = n - 2; i >= 0; i--){
if(a[i] < a[i + 1]){
pos1 = i;
break;
}
}
if(pos1 == -1){
cout << -1 << endl;
return;
}
for(int i = n - 1; i > pos1; i--){
if(a[i] > a[pos1]){
pos2 = i;
break;
}
}
swap(a[pos1], a[pos2]);
sort(a.begin() + pos1 + 1, a.end());
cout << a << endl;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--){
solve();
}
return 0;
}
这题还有一种巧妙的解法,用 库中的
函数,这个函数会尝试将给定范围内的元素调整为字典序的下一个排列。
如果存在下一个排列,它会返回 ,并且将元素排列成下一个字典序排列。
如果不存在下一个排列(即当前排列已经是字典序的最大排列),它会返回 ,并将元素排列成最小排列(即升序排列)。
时间复杂度:
ACcode2
#include <iostream>
#include <algorithm>
#define endl '\n'
using namespace std;
void solve(){
string a;
cin >> a;
if(next_permutation(a.begin(), a.end())){
cout << a << endl;
}
else{
cout << -1 << endl;
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;
cin >> T;
while(T--){
solve();
}
return 0;
}
I
考察点:模拟、STL、字符串
按题意模拟,小明喜欢的课和喜欢程度用,看一门课选没选过可以用
或
,课表可以用数组或
存,按题意处理每次查询、改变对应的信息即可。
时间复杂度:
ACcode
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
vector<vector<string>> a(8, vector<string>(6, "None"));
map<string, int> ma;
set<string> se;
int n, m;
cin >> n >> m;
vector<string> s(n);
for(int i = 1; i <= 7; i++){
a[i][5] = "SYUCTACM";
}
for(int i = 1; i <= 5; i++){
a[6][i] = "SYUCTACM";
}
a[7][1] = a[7][2] = "SYUCTACM";
a[3][3] = a[3][4] = "SYUCTACM";
for(int i = 0; i < n; i++){
cin >> s[i];
}
for(int i = 0; i < n; i++){
int x;
cin >> x;
ma[s[i]] = x;
}
for(int i = 0; i < m; i++){
string t;
int b, c;
cin >> t >> b >> c;
if(!ma.count(t)) continue;
if(se.count(t)) continue;
if(a[b][c] == "SYUCTACM") continue;
if(a[b][c] == "None"){
a[b][c] = t;
se.insert(t);
}
else{
if(ma[a[b][c]] < ma[t]){
se.erase(a[b][c]);
a[b][c] = t;
se.insert(t);
}
}
}
for(int i = 1; i <= 7; i++){
for(int j = 1; j <= 5; j++){
cout << a[i][j] << ' ';
}
cout << endl;
}
return 0;
}
J
考察点:vector去重排序、双指针/二分
这道题可以先将小明的手牌全部存到里,再去重排序一下,问题就转化成了:求满足
的最长子数组
~
,暴力显然做不了,可以用双指针或二分来进行优化。
双指针解法:指针遍历区间右端点,
指针遍历区间左端点,每次满足条件时用区间长度更新答案即可。
时间复杂度:
ACcode1
#include <iostream>
#include <algorithm>
#include <vector>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
vector<int> a(n);
for(int i = 0; i < n; i++){
cin >> a[i];
}
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
n = a.size();
int res = 0;
for(int i = 0, j = 0; i < n; i++){
while(j < i && a[i] - a[j] - (i - j) > k){
j++;
}
res = max(res, i - j + 1);
}
cout << min(res + k, m) << endl;
return 0;
}
二分解法:循环遍历每个位置作为左端点,二分查找第一个满足条件的右端点的位置,用区间长度更新答案即可。
时间复杂度:
ACcode2
#include <iostream>
#include <algorithm>
#include <vector>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
vector<int> a(n);
for(int i = 0; i < n; i++){
cin >> a[i];
}
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
n = a.size();
int res = 0;
for(int i = 0; i < n; i++){
int l = i, r = n - 1;
while(l < r){
int mid = l + r + 1 >> 1;
if(a[mid] - a[i] - (mid - i) <= k) l = mid;
else r = mid - 1;
}
res = max(res, l - i + 1);
}
cout << min(res + k, m) << endl;
return 0;
}