2022秋季体验营C++试题-解析
2022秋季体验营C++试题-解析
前言
题目传送:https://www.luogu.com.cn/training/168860
本次题目我已经上传到洛谷,不过洛谷的SPJ,初中组最后一题分值我没有处理,评分不准确,但也可以测试。
另外根据本次测试,大家也发现了自己的问题,我这里大概备注几点致命问题
-
准备好了吗,我要开车了。
-
文件名不按照要求填写
文件名要求与题面说明一致,因为主办方在收到文件后,会使用脚本对不合法文件删除。
如果你的文件不符合要求就会被删除,导致最后自己的文件夹下是空的。
至于是否保存在子文件夹下,保存在那个目录,需要根据官方要求来。
四川这边目前不需要建立子文件夹,也就是如下格式(每年都会发说明,注意看)
规定的文件目录\
water.cpp
bamboo.cpp
home.cpp
当然如果因为什么使你对此有疑问且不能解决,可以尝试2种方案都用,也就是再复制一份相同的程序,放在子文件夹下。
- 是否开启文件输入输出,freopen
请注意在比赛结束前10分钟,不要在答题了。
这时候务必关闭自己的IDE,并检查程序的命名,文件输入输出是否正确,文件关闭,有无运行报错等易发现的信息。
确定没有问题之后关闭IDE,准备提交。
- 正确骗分
所谓的骗分,不是说你把样例输出,这样基本是会WA哭的。
而是说,我们在想不到正解AC的情况下,通过一些简单、暴力、奇怪的思路或者题目的一些特殊数据来尽可能拿到部分分数。
比如本次初中组 T2,T3 就可以。不要小看这一点,或许这就是 1=,2= 的区别了。
- Memory Limit(内存限制)
const int N=1e5+10;
int a[N][N];
其实,我们可以简单计算一下空间大小:\(4*N*N=4e10B ≈ 4e4MB > 512MB\)
或者 cout<<1.0*sizeof(a)/1024/1024<<"MB";
所以可不敢这样写的!!!
而且一般这样本地运行就会报错的,除非......吃一堑长一智吧!
- 关于大家提交的文件中部分格式的说明
以下将为大家展示一些错误的格式,避免踩坑。
(1)提交过多文件不会有坏的影响,但是这并不利于自己检查文件的完整性,所以如果有足够的时间,还是对不必要的文件进行删除,仅保留cpp文件即可。但是需要注意的是,不要删除错误了。
(2)在自己本地的时候没有开启文件类型显示,以至于自己多加了一个 .cpp,那么这样整个源程序名就变为:xx.cpp.cpp,这里大家一定要注意,开启文件类型显示。
- 开启文件类型显示:文件夹选项中,取消隐藏勾选已知文件类型的扩展名
![image]()
小学C++组:
挑水(water)
思路:最少次数,那每次挑水就要最多,选择最大的桶mx。
\(ans = ceil(1.0*m/(2*mx))\)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,a[N],mx=-1;
int main() {
freopen("water.in","r",stdin);
freopen("water.out","w",stdout);
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++) {
if(mx < a[i]) mx=a[i]; //最大桶
}
int ans=ceil(1.0*m/(2*mx));
cout<<ans;
fclose(stdin), fclose(stdout);
return 0;
}
挖竹笋(bamboo)
思路:采过就标记,计数。

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int a[N][N],n,k,ans=0;
int main() {
freopen("bamboo.in","r",stdin);
freopen("bamboo.out","w",stdout);
cin>>n>>k;
for(int i=1; i<=k; i++) {
int x1,x2,y1,y2; cin>>x1>>y1>>x2>>y2;
for(int x=x1; x<=x2; x++) {
for(int y=y1; y<=y2; y++) {
if(!a[x][y]) a[x][y]=1, ans++;// 采摘
}
}
}
cout<<ans;
fclose(stdin), fclose(stdout);
return 0;
}
建房子(home)
思路:枚举答案[1,1000000],判断合理性
- 要求最大值,那么可以逆序枚举答案 x
- check(x):判断是否能生产 m 根长度为 x 的竹子。
但是这样发现复杂度较高:1e6*1e6, 所以我们需要一个 O(nlogn)的算法,于是二分答案就可以了。

- 由于数据较大,本题建议使用scanf/printf,使用内联函数或者不使用check函数,如下程序。
当数据量 1e6级别的时候,它们的影响还是比较大的。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int n,m,a[N],b[N];
int main() {
freopen("home.in","r",stdin);
freopen("home.out","w",stdout);
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>a[i]>>b[i];
int l=1, r=1e6; // 答案区间 [l,r]
while(l<r) {
int mid=(l+r+1)/2; LL num=0; // 注意 long long
for(int i=1; i<=n; i++) num += a[i]/mid*b[i];
if(num>=m) l=mid;
else r=mid-1;
}
cout<<l;
fclose(stdin), fclose(stdout);
return 0;
}
初中C++组
本次初中组三道题目都很考察代码能力,都是属于模拟类型的题目,细节较多。
足球赛(football)
-
思路:最终的得分以及平局都比较容易计算, 但是要注意(初始比分0:0 也算作一次打平)。
-
球赛中最大的「翻盘」:翻盘一定是出现在平局之后的,判断每个平局后会不会翻盘,如果会,就左右查找连续胜利次数,也就是翻盘量。
#include<bits/stdc++.h>
using namespace std;
const int N=310;
int n, a[N], p[10], b[N], cnt=0;
int main() {
freopen("football.in", "r", stdin);
freopen("football.out", "w", stdout);
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
p[3]=1, p[4]=2;
for(int i=1; i<=n; i++) {
p[a[i]]++;
if(p[1]==p[2]) p[3]++, b[++cnt]=i;
}
for(int i=1; i<=cnt; i++) {
// 第 k 局为平局, f 为 第 k 局胜者,也就是翻盘者
int k=b[i], f=a[b[i]], temp=0;
if(k==n || f!=a[k+1]) continue; // 无法翻盘
// 左右查找连续胜利次数,也就是翻盘量
for(int j=k-1; j>=1; j--) {
if(f==a[j]) temp++; else break;
}
for(int j=k; j<=n; j++) {
if(f==a[j]) temp++; else break;
}
p[4] = max(p[4], temp); // 最大翻盘
}
cout<<p[1]<<" "<<p[2]<<endl;
cout<<p[3]<<endl<<p[4]<<endl;
fclose(stdin), fclose(stdout);
return 0;
}
倒酒(pourwine)
思路:既然要让最多的杯子空,那么也就是尽量用容积大的杯子去装就行了。
- 安照桶的容积升序排序,最后将前面小容积桶置空,就可以获得最大的空桶数量
- 其实这个题目可以骗分 20~40,20%的数据,桶是一样的,求出最大空桶数量就有40分
- 最后输出的时候需要按照ID排序
- 当然,满分思路就是个模拟,不过细节较多
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
struct T {
int id,t,z;
} p[N];
bool cmp1(T a, T b) {
return a.z < b.z;
}
bool cmp2(T a, T b) {
return a.id < b.id;
}
int main() {
freopen("pourwine.in", "r", stdin);
freopen("pourwine.out", "w", stdout);
int n; cin>>n;
for(int i=1; i<=n; i++) cin>>p[i].t>>p[i].z, p[i].id=i;
// 安照桶的容积升序排序,最后将前面小容积桶置空,就可以获得最大的空桶数量
sort(p+1, p+1+n, cmp1);
int cnt=n;
for(int i=1; i<=n; i++) {
// 第 cnt桶满了,换下一个最大桶装水
while(p[cnt].z-p[cnt].t==0) cnt--;
if(cnt < 1 || i>=cnt) break;
int pcntt=p[cnt].z-p[cnt].t;
if(pcntt > 0) {// 第 i 桶水空了,没空
if(pcntt >= p[i].t)
p[cnt].t += p[i].t, p[i].t=0;
if(pcntt < p[i].t)
p[cnt].t += pcntt, p[i].t -= pcntt, i--;
}
}
int ans=0;
for(int i=1; i<=n; i++) if(p[i].t==0) ans++;
cout<<ans<<endl;
sort(p+1, p+1+n, cmp2);
for(int i=1; i<=n; i++) cout<<p[i].t<<" ";;
fclose(stdin), fclose(stdout);
return 0;
}
玩具(toy)
思路:好像没有思路,也是一个模拟题,直接看方案
-
方案1:枚举区间 [l,r],O(n)判断,整体复杂度 \(O(n^3)\), score:7
-
方案2: 枚举颜色数量 [1,26],双指针模拟,复杂度 26*O(n),AC
-
注意:double val=num/(r-l+1) 是浮点数,严格来讲是不准确的,一般情况下可以。最好还是用分数形式描述,如下:
\(\frac{x1}{y1} > \frac{x2}{y2} ==> \frac{x1*y2}{y1*y2} > \frac{x2*y1}{y1*y2}\)
void slove1() {
long long x1=INF,y1=1,x2,y2;
int x=0, y=0;
for(int l=0; l<a.size(); l++) {
for(int r=l+1; r<a.size(); r++) {
int vis[26]= {0}, num=0;
for(int i=l; i<=r; i++) vis[a[i]-'a']++;
for(int i=0; i<26; i++) if(vis[i]) num++;
x2=num, y2=(r-l+1);
if(x1*y2 > x2*y1) x1=x2, y1=y2, x=l, y=r;
}
}
cout<<x+1<<" "<<y+1<<endl;
}


浙公网安备 33010602011771号