锐评
-
本套题目风格和天梯赛相近,难度略高于天梯赛。
-
IOI赛制是可以骗分的,对多少测试点就给多少分,比如
题直接输出
、
题直接输出
都是有分的,F题、H题直接给输入原样输出也是有分的,比赛的时候不会别空着,IOI赛制没有罚时,错了也不扣分,可以大胆尝试。
-
如果天梯赛之前字符串常用的函数(
)还不会就都别去打了。
-
打天梯赛的没事好好做做往年的题,做多了就会发现天梯出题是有规律的:https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7
L1-1
直接输出即可,注意因为图片中的“相”字打错成了“柤“,题目也要输出相同的内容。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cout << "2026年,ICPC,我们再柤会!" << endl;
return 0;
}
L1-2
首先当 是奇数时,无法恰好覆盖,证明如下:
的砖块面积为
,所以覆盖的总面积也一定是
的整数倍,也就是说覆盖的面积只能是偶数不能是奇数。
若 是偶数,我们把砖块竖着放置,每行
块,放
行,如下方左图。
若 是偶数,我们把砖块横着放置,每列
块,放
列,如下方右图。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int a, b;
cin >> a >> b;
if(a % 2 && b % 2) cout << "No" << endl;
else cout << "Yes" << endl;
return 0;
}
L1-3
按题意模拟即可。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int W, T, ed, M, U, ud;
cin >> W >> T >> ed >> M >> U >> ud;
if(M == 1){
cout << "Repair" << endl;
cout << "No" << endl;
}
else{
if(T == W){
cout << "Run" << endl;
cout << "No" << endl;
}
else{
if(ed == ud){
cout << "Stop" << endl;
if(T + U > W) cout << "No" << endl;
else cout << "Yes" << endl;
}
else{
cout << "Run" << endl;
cout << "No" << endl;
}
}
}
return 0;
}
L1-4
首先要分别得到的 二进制第
位及以下的部分
和
的 二进制第
位以上的部分
:
-
对于
,可以用一个二进制第
位及以下全是
、第
位以上全是
的数,也就是
来和
进行按位与
得到。
-
对于
,直接用
即可得到。
接着,按题意模拟,判断和
,也就是
的大小:
-
如果
,直接舍弃
,答案就是
。
-
如果
,将
舍去,给
的二进制第
位加
,答案就是
。
另外,通过二进制推导可以得到,答案其实就是:。
#include <iostream>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
int mask = (1 << k) - 1;
int low = n & mask;
int high = n - low;
if(low >= (1 << (k - 1))) cout << high + (1 << k) << endl;
else cout << high << endl;
return 0;
}
#include <iostream>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
int res = ((n + (1LL << (k - 1))) >> k) << k;
cout << res << endl;
return 0;
}
L1-5
这题的题目其实叫 “//是什么意思”,但牛客的系统似乎直接也把这句话当注释忽略了
用循环不断读入字符串,按顺序从左到右、从上到下遍历每个字符,分别用两个变量标记一下当前是不是在多行注释中、是不是在字符串中。
- 如果遇到
/*,且当前不在字符串和注释中,进入多行注释,遍历所有的字符都直接输出,此时如果遍历到
*/,离开多行注释。 - 如果遇到
",且不在注释中,进入字符串,遍历所有的字符都直接原样输出,此书如果遍历",离开字符串。
模拟即可。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
string s;
bool in_string = false;
bool in_block = false;
while(cin >> s){
for(int i = 0; i < s.size(); i++){
if(in_block) {
if(i + 1 < s.size() && s[i] == '*' && s[i + 1] == '/'){
cout << "##";
i++;
in_block = false;
}
else cout << '#';
continue;
}
if(!in_string){
if(i + 1 < s.size() && s[i] == '/' && s[i + 1] == '/'){
cout << "##";
i += 2;
while(i < s.size()){
cout << '#';
i++;
}
break;
}
if(i + 1 < s.size() && s[i] == '/' && s[i + 1] == '*'){
cout << "##";
i++;
in_block = true;
continue;
}
}
if(s[i] == '"') in_string = !in_string;
cout << s[i];
}
cout << endl;
}
return 0;
}
L1-6
因为每年天梯赛字符串题的解答率都不尽如人意,因此出题组从几年前开始决定:每年的天梯赛的 15 分一定会有一道字符串题,另外一道则一定不是字符串题。
天梯赛每年必考的字符串操作,字符串中的常用函数一定要会用且记住。
- 对于操作1:循环遍历每个字符,在里面再套一次循环遍历连续的相同的字符,统计数量。接着,在循环里不建议直接修改
,会影响
的大小,写不好极易出现边界错误,可以新开一个空串记录操作后的
,遍历的时同时按替换规则一段一段往后接即可。
- 对于操作2:首先用
找到
在
中第一次出现的位置,用
找到
在
中最后一次出现的位置。
-
- 如果找不到 /
在
前面 /
和
有重叠部分:
不变。
- 否则直接将
替换成
之间的子串,或者将两端多余的地方删掉即可。
- 如果找不到 /
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
string s;
cin >> n >> s;
for(int i = 0; i < n; i++){
char op;
cin >> op;
if(op == 'C'){
string t;
int p = 0;
while(p < s.size()){
char ch = s[p];
int cnt = 0;
while(p < s.size() && s[p] == ch){
cnt++;
p++;
}
t += to_string(cnt);
t += ch;
}
s = t;
}
else{
string s1, s2;
cin >> s1 >> s2;
int p1 = s.find(s1);
int p2 = s.rfind(s2);
if(p1 != -1 && p2 != -1 && p1 + s1.size() <= p2) s = s.substr(p1, p2 + s2.size() - p1);
}
}
cout << s << endl;
return 0;
}
L1-7
模拟时钟的变化,分别用变量来记录起始的小时、起始的分钟、目标的小时、目标的分钟,从起始时间开始,按时间规则模拟时间的变化,每次记录变化前的值和变化后的值,将两个值进行比对,判断有几位不同,累加到答案即可。
输入时间可以用格式化输出,判断不同位数时也可以用
拼接成字符串后再判断。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
// ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int h, m, eh, em;
scanf("%d:%d %d:%d", &h, &m, &eh, &em);
int res = 0;
while(h != eh || m != em){
int a1 = h / 10;
int a2 = h % 10;
int a3 = m / 10;
int a4 = m % 10;
m++;
if(m == 60){
m = 0;
h++;
if(h == 24) h = 0;
}
int b1 = h / 10;
int b2 = h % 10;
int b3 = m / 10;
int b4 = m % 10;
if(a1 != b1) res++;
if(a2 != b2) res++;
if(a3 != b3) res++;
if(a4 != b4) res++;
}
cout << res << endl;
}
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
// ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int h, m, eh, em;
scanf("%d:%d %d:%d", &h, &m, &eh, &em);
int res = 0;
while(h != eh || m != em){
char s1[6], s2[6];
sprintf(s1, "%02d%02d", h, m);
m++;
if(m == 60){
m = 0;
h++;
if(h == 24) h = 0;
}
sprintf(s2, "%02d%02d", h, m);
for(int i = 0; i < 4; i++){
if(s1[i] != s2[i]) res++;
}
}
cout << res << endl;
return 0;
}
L1-8
平移次数 很大,如果直接移动会超时。可以利用取模运算优化,因为平移
次行/
此列相当于没有移动。
然后模拟循环移位的操作即可,用一个临时数组存平移后的结果,再复制回原矩阵即可。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
int n, m;
cin >> n >> m;
char a[25][25];
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> a[i][j];
}
}
int q;
cin >> q;
while(q--){
int op, l, r, k;
cin >> op >> l >> r >> k;
l--, r--;
if(op == 1){
int t = k % m;
for(int i = l; i <= r; i++){
char tmp[25];
for(int j = 0; j < m; j++){
tmp[(j + t) % m] = a[i][j];
}
for(int j = 0; j < m; j++){
a[i][j] = tmp[j];
}
}
}
else{
int t = k % n;
for(int j = l; j <= r; j++){
char tmp[25];
for(int i = 0; i < n; i++){
tmp[(i + t) % n] = a[i][j];
}
for(int i = 0; i < n; i++){
a[i][j] = tmp[i];
}
}
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cout << a[i][j];
}
cout << endl;
}
return 0;
}
L2 -1
用队列来模拟当前在排队的序列,将序列前两个选手的实力值取出,其余选手的实力值入队。
循环模拟次比赛,每次比赛比较两位选手的实力值,实力值高的选手连胜场次
,实力值低的选手入队,如果实力值高的选手连胜场次达到
,在实力值低的选手入队后也入队。场上人数少于两人就从队首出队补位,新上场的选手连胜场次清零。模拟即可。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
struct Player{
int val, cnt;
};
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
queue<Player> q;
for(int i = 0; i < n; i++){
int s;
cin >> s;
q.push({s, 0});
}
Player p1 = q.front();
q.pop();
Player p2 = q.front();
q.pop();
for(int i = 1; i <= k; i++){
if(i == k){
int a = p1.val, b = p2.val;
if(a > b) swap(a, b);
cout << a << ' ' << b << endl;
}
if(p1.val > p2.val){
p2.cnt = 0;
q.push(p2);
p1.cnt++;
if(p1.cnt == 2){
p1.cnt = 0;
q.push(p1);
p1 = q.front();
q.pop();
p2 = q.front();
q.pop();
}
else{
p2 = q.front();
q.pop();
}
}
else{
p1.cnt = 0;
q.push(p1);
p2.cnt++;
if(p2.cnt == 2){
p2.cnt = 0;
q.push(p2);
p1 = q.front();
q.pop();
p2 = q.front();
q.pop();
}
else{
p1 = q.front();
q.pop();
}
}
}
return 0;
}
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, k;
cin >> n >> k;
queue<int> q;
for(int i = 0; i < n; i++){
int x;
cin >> x;
q.push(x);
}
int a = q.front();
q.pop();
int b = q.front();
q.pop();
int cnt = 0;
for(int i = 1; i <= k; i++){
if(i == k){
if(a > b) swap(a, b);
cout << a << ' ' << b << endl;
}
int winner, loser;
if(a > b){
winner = a;
loser = b;
cnt++;
}
else{
winner = b;
loser = a;
cnt = 1;
}
q.push(loser);
if(cnt == 2){
q.push(winner);
cnt = 0;
a = q.front();
q.pop();
b = q.front();
q.pop();
}
else{
a = winner;
b = q.front();
q.pop();
}
}
return 0;
}
L2-2
用三个变量记录答案,遍历一遍数组根据当前位置的数的奇偶,判断更新对应的变量即可。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
int i = -1, j = -1, k = -1;
for(int p = 1; p <= n; p++){
int x;
cin >> x;
if(i == -1){
if(x % 2) i = p;
}
if(i != -1 && j == -1){
if(x % 2 == 0){
j = p;
continue;
}
}
if(j != -1 && k == -1){
if(x % 2 == 0) k = p;
}
if(k != -1){
if(x % 2){
cout << "Yes" << endl;
cout << i << ' ' << j << ' ' << k << ' ' << p << endl;
return 0;
}
}
}
cout << "No" << endl;
}
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
int i = -1, j = -1, k = -1;
for(int p = 1; p <= n; p++){
int x;
cin >> x;
if(i == -1){
if(x % 2) i = p;
}
else if(j == -1){
if(x % 2 == 0) j = p;
}
else if(k == -1){
if(x % 2 == 0) k = p;
}
else{
if(x % 2){
cout << "Yes" << endl;
cout << i << ' ' << j << ' ' << k << ' ' << p << endl;
return 0;
}
}
}
cout << "No" << endl;
}
L2-3
解法1:手机重量越大,要求越严格,满足单调性,可以二分答案。
设计函数,如果手机重量为
,问题可以转化为:是否能找到
对木棍,使得每一对乘积都
。
可以对数组排序后通过双指针来解决:
使用两个指针 :
- 如果
,说明
可以和
配对,合法对数加
,
,将指针移到下一位置。
- 如果
,说明
太小,即使配最大
也不够,所以
继续看下一个
。
最后比较合法配对数和的大小即可。
如果合法配对数大于等于,当前
可以达到,
继续向右半边尽可能找更大的答案。
如果合法配对数小于,当前
大了,达不到,
继续向左半边找可能满足的答案。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using LL = long long;
int a[100005];
int n, m;
bool check(LL x){
int cnt = 0;
int i = 0, j = n - 1;
while(i < j){
if((LL)a[i] * a[j] >= x){
cnt++;
i++;
j--;
}
else i++;
}
return cnt >= m;
}
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];
}
sort(a, a + n);
LL l = 1, r = LLONG_MAX;
while(l < r){
LL mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
return 0;
}
解法2:贪心。将 按 从大到小的顺序排序后,最优方案即为:第
个支架用长度为
和
的木棍制作,第
个支架用长度为
和
的木棍制作,以此类推。
因此枚举 ,答案为
。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using LL = long long;
int a[100005];
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 >> a[i];
}
sort(a, a + n, greater<>());
LL res = LLONG_MAX;
for(int i = 0;i < m;i++){
LL t = (LL)a[i] * a[2 * m - 1 - i];
res = min(res, t);
}
cout << res << endl;
return 0;
}
L2-4
贪心配对,。
首先用递归遍历统计每个节点的子树大小(节点数量)。
然后用进行贪心配对,遍历每个节点
的所有子树,找到节点数量最大的子树并记录其根节点,比较该子树当前未用于配对的节点数量和其他所有
的子树的节点数量和:
- 如果小于,那显然所有子树未用于配对的节点都可以两两配对,直接累加答案返回即可。
- 如果大于等于,将其他所有子树的所有节点都和该最大子树未用于配对的节点配对,累加答案,由于配对后最大子树内部还有部分节点未配对,接着递归处理该最大子树。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
using LL = long long;
const int N = 200005;
vector<int> g[N];
int sz[N];
LL res;
void dfs_sz(int u){
sz[u] = 1;
for(auto v : g[u]){
dfs_sz(v);
sz[u] += sz[v];
}
}
void dfs(int u, int k){
int sum = 0;
int mx = -1;
for(auto v : g[u]){
sum += sz[v];
if(mx == -1 || sz[v] > sz[mx]) mx = v;
}
if(sum == 0) return;
if(sz[mx] - k <= sum - sz[mx]){
res += (sum - k) / 2;
return;
}
int cnt = sum - sz[mx];
res += cnt;
int nk = max(0, k + cnt - 1);
dfs(mx, nk);
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
for(int i = 2; i <= n; i++){
int p;
cin >> p;
g[p].push_back(i);
}
dfs_sz(1);
res = 0;
dfs(1, 0);
cout << res << endl;
return 0;
}
L3-1
https://ac.nowcoder.com/acm/contest/90070/E
L3-2
https://ac.nowcoder.com/acm/contest/86387/F

京公网安备 11010502036488号