【天梯赛训练记录】GPLT 团体程序设计天梯赛训练1
训练情况
赛后反思
L2-2一道显然的树的父亲标识法,求树的深度,但是调了半天,写了记忆化还是超时丢了两分,L3-2是 DP,但是暴力枚举set去重拿满18分,后续还需要加强DP训练
L1-1
巨恶心的模拟题,一道需要特别注意换行和空格处理的问题,一队 10 人,我们按学校的顺序遍历,如果当前学校仍有队员则往下分配座位即可,我们需要另外记录一下上一个分配座位的学校,如果当前学校与上个学校相同需要隔座位,输出 10 个一组,注意行末空格和换行的问题,格式错误了好几发
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 103;
int n;
int a[N];
vector<int> ans[N];
int tot = 0;
signed main(){
int sum = 0;
cin>>n;
for(int i = 1;i<=n;i++) cin>>a[i],a[i]*=10,sum+=a[i];
int last = 0;
int cnt = 10000;
while(cnt--){
for(int i = 1;i<=n;i++){
if(a[i]){
if(i == last) ++tot;
ans[i].emplace_back(++tot);
a[i]--;
last = i;
}
}
}
for(int i = 1;i<=n;i++){
cout<<"#"<<i<<endl;
for(int j = 0;j<ans[i].size();j++){
if(j%10==9) cout<<ans[i][j];
else cout<<ans[i][j]<<" ";
if(i == n && j == ans[i].size() - 1) return 0;
if(j%10==9) cout<<endl;
}
}
return 0;
}
L1-2
这题空间卡的很死,大力 DFS 枚举塞进数组里喜提空间超限,对于长度为 n 的字符串,显然有 \(26^n\) 种字符串,所以我们倒数第几个可以给它搞正过来,这题步长 1 的字符串可以等效转换为 26 进制,所以我们直接写个十进制转 26 进制即可,进制转换模板是 % 26 / 26,注意处理一下 0 对应的 a,while循环有些逆天情况会不输出 a
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int a,b; cin>>a>>b;
int ans = 1ll;
for(int i = 1;i<=a;i++) ans*=26ll;
b = ans - b;
char c[100];
int tot = 0;
if(b == 0){
for(int i = 1;i<=a;i++) cout<<"a";
return 0;
}
while(b){
c[++tot] = 'a'+(b%26ll);
b/=26ll;
}
while(tot < a) c[++tot] = 'a';
for(int i = tot;i;i--) cout<<c[i];
return 0;
}
L1-3
白送题,8 折就是乘 0.8,答案就是两数相乘/10,再保留两位小数
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
double a,b; cin>>a>>b;
cout<<fixed<<setprecision(2)<<a*b/10<<endl;
return 0;
}
L1-4
白送题,按照题目所述直接输出
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
cout<<"2018"<<endl;
cout<<"wo3 men2 yao4 ying2 !"<<endl;
return 0;
}
L1-5
白送题,计算 a+b,循环一下输出 Wang! 即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int a,b; cin>>a>>b;
for(int i = 1;i<=a+b;i++) cout<<"Wang!";
return 0;
}
L1-6
白送题,显然颠倒的过程是上下对称,然后再左右对称,最后判断颠倒后是否相等即可,相等需要多输出一行,这题难在代码实现
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 103;
string s[N];
string t[N];
int main(){
char c; int n;
cin>>c>>n;
getchar();
for(int i = 1;i<=n;i++){
getline(cin,s[i]);
}
for(int i = 1;i<=n;i++){
t[i] = s[n-i+1];
}
for(int i = 1;i<=n;i++){
reverse(t[i].begin(),t[i].end());
}
bool flag = false;
for(int i = 1;i<=n;i++) if(s[i] != t[i]) flag = true;
if(flag){
for(int i = 1;i<=n;i++){
for(int j = 0;j<n;j++){
if(t[i][j] == ' ') cout<<' ';
else if(t[i][j] == '@') cout<<c;
}
cout<<endl;
}
} else {
cout<<"bu yong dao le"<<endl;
for(int i = 1;i<=n;i++){
for(int j = 0;j<n;j++){
if(t[i][j] == ' ') cout<<' ';
else if(t[i][j] == '@') cout<<c;
}
cout<<endl;
}
}
return 0;
}
L1-7
这题有个坑点,得到至少 1 名评委的认可,所以如果某个人都没得到评委认可,无论什么情况他都是输,需要多判断一下这个,其他直接模拟分数加的过程,最后判断哪个大输出哪个即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int a,b; cin>>a>>b;
int acnt = 0,bcnt = 0;
for(int i = 1;i<=3;i++){
int x; cin>>x;
if(x == 0) acnt++;
else if(x == 1) bcnt++;
}
if(acnt == 0){
cout<<"The winner is b: "<<b<<" + "<<bcnt<<endl;
return 0;
}
if(bcnt == 0){
cout<<"The winner is a: "<<a<<" + "<<acnt<<endl;
return 0;
}
if(a>b) cout<<"The winner is a: "<<a<<" + "<<acnt<<endl;
else cout<<"The winner is b: "<<b<<" + "<<bcnt<<endl;
return 0;
}
L1-8
白送题,数列求和再求平均数再除二,最后数列遍历一遍,判断差的绝对值哪个更小更新答案即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n; cin>>n;
vector<string> a(n + 1);
vector<int> b(n + 1);
int sum = 0;
for(int i = 1;i<=n;i++) cin>>a[i]>>b[i],sum+=b[i];
sum /= n;
sum /= 2;
string ans;
int now = INT_MAX;
for(int i = 1;i<=n;i++){
if(abs(b[i] - sum) < now){
now = abs(b[i] - sum);
ans = a[i];
}
}
cout<<sum<<" "<<ans<<endl;
return 0;
}
L2-1
并查集维护联通块,白送的并查集模板,对于打击掉的城市,我们使用标记一下,然后连边并查集维护联通的时候遇到有标记的直接跳过,最后判断每个点是否是孤立的(fa[x] = x)即可,我这边直接扔到 set 里面,判断联通块个数是否等于城市数
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 3;
int fa[N];
int Find(int x){
if(fa[x] == x) return x;
return fa[x] = Find(fa[x]);
}
void Union(int x,int y){
x = Find(x);
y = Find(y);
if(x == y) return;
fa[y] = x;
}
int main(){
int n,m; cin>>n>>m;
vector<int> u(m + 1),v(m + 1);
for(int i = 1;i<=m;i++) cin>>u[i]>>v[i];
int q; cin>>q;
while(q--){
vector<bool> vis(n + 1);
for(int i = 1;i<=n;i++) fa[i] = i;
int k; cin>>k;
for(int i = 1;i<=k;i++){
int x; cin>>x;
vis[x] = 1;
}
for(int i = 1;i<=m;i++){
if(vis[u[i]] || vis[v[i]]) continue;
Union(u[i],v[i]);
}
set<int> se;
for(int i = 1;i<=n;i++) se.insert(Find(i));
if(se.size() == n) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
L2-2
这道题我分数没有拿满,这题显然可以从子节点往父节点 x = fa[x] 暴力跳,同时记录每个点的深度,但是会被卡时间,顺带写了一手记忆化,记录当前位置的深度,如果遇到有计算过的直接加答案,不需要继续往上跳,多了一些些分
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n; cin>>n;
vector<int> a(n + 1);
vector<int> dp(n + 1);
vector<int> cnt(n + 1);
for(int i = 1;i<=n;i++) cin>>a[i];
for(int i = 1;i<=n;i++){
int x = a[i];
int now = 0;
while(x != -1){
if(!cnt[x]) now++;
else {
now += cnt[x]+1;
break;
}
x = a[x];
}
cnt[i] = now;
}
int ma = 0;
for(int i = 1;i<=n;i++){
ma = max(ma,cnt[i]);
}
vector<int> ans;
cout<<ma+1<<endl;
for(int i = 1;i<=n;i++) if(ma == cnt[i]) ans.emplace_back(i);
for(int i = 0;i<ans.size();i++){
if(i == ans.size()-1) cout<<ans[i];
else cout<<ans[i]<<" ";
}
return 0;
}
L2-3
这题金额计算比较简单,满足条件的直接按照题目所述加上去即可,难在排序取排名的情况,特别是并列的情况,我们考虑使用桶排序,把分数全部扔进桶里,使用一个变量记录当前分数对应的排名,最后从大到小遍历,遇到有至少一个的排名+1,记录完之后再加上桶里面分数的个数,这样处理并列的问题
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 3;
int n,g,k;
int tong[103];
struct node{
string a;
int b;
}a[N];
bool cmp(node x,node y){
if(x.b == y.b) return x.a < y.a;
else return x.b > y.b;
}
int main(){
cin>>n>>g>>k;
int ans = 0;
for(int i = 1;i<=n;i++){
cin>>a[i].a>>a[i].b;
if(a[i].b >= g && a[i].b <= 100) ans += 50;
else if(a[i].b >= 60 && a[i].b < g) ans += 20;
}
sort(a + 1,a + 1 + n,cmp);
for(int i = 1;i<=n;i++){
tong[a[i].b]++;
}
map<int,int> rk;
int now = 0;
for(int i = 100;~i;i--){
if(tong[i]){
now++;
rk[i] = now;
now += tong[i]-1;
}
}
cout<<ans<<endl;
int i = 1;
while(i<=n && rk[a[i].b] <= k){
cout<<rk[a[i].b]<<" "<<a[i].a<<" "<<a[i].b<<endl;
i++;
}
return 0;
}
L2-4
这题不会,直接瞪眼,发现一个样例答案刚好是最后两个数,随手试一发,输出最后两个数,意外拿了两分,稳赚不亏
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
int main(){
cin>>n>>m;
getchar();
for(int i = 1;i<=m;i++){
string s; cin>>s;
getline(cin,s);
}
int a,b; cin>>a>>b;
cout<<a<<" "<<b<<endl;
return 0;
}
L3-2
显然去重的问题扔给set,我们考虑枚举删哪个点,我们直接暴力 \(O(n^4)\) 模拟,枚举删掉三个点的位置,插入到 set 里面去重,直接输出集合大小即可,这题正解是 DP ,但我不会
点击查看代码
#include <bits/stdc++.h>
using namespace std;
set<string> se;
int main(){
string s; cin>>s;
int n = s.size();
se.insert(s);
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
for(int k = 0;k<n;k++){
string ss;
for(int l = 0;l<n;l++){
if(l == i || l == j || l == k) continue;
ss += s[l];
}
se.insert(ss);
}
}
}
// for(auto i:se){
// cout<<i<<endl;
// }
cout<<se.size()<<endl;
return 0;
}
L3-3
题目里说三点贡献答案是 0.000,测试点里应该会有这种情况,直接无脑输出 0.000,水了两分,稳赚不亏
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main(){
cout<<"0.000";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具