2023团队程序设计天梯赛选拔赛

1.Ltree的数据结构

T322022 Ltree的数据结构 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

主次关键字的排序

用结构体

比赛过程中,其它都很顺利,问题出在了名次上,一直找不到错误点,满分25分,只对了一个测试点,拿了两分,其它都是RE

比赛代码(错误):

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=10010;
LL n,m,k;
struct Stu{
    string s;
    int x;
    bool operator<(const Stu &W)const{
        if(x!=W.x) return x>W.x;
        return s<W.s;
    }
}q[N];
int idx[N];
LL sum;
int p;
int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        cin>>q[i].s>>q[i].x;
        if(q[i].x>=60&&q[i].x<m) sum+=20;
        if(q[i].x>=m&&q[i].x<=100) sum+=50;
    }
    sort(q,q+n);
    idx[0]=1;
    LL cnt=1;
    for(int i=1;;i++){
        cnt++;
        if(q[i].x==q[i-1].x){
            idx[i]=idx[i-1];
        }
        else{
        idx[i]=cnt;
        }
        if(idx[i]==k){
            p=i;
            break;
        }
    }
    LL cnt2=0;
    for(int i=p+1;;i++){
        if(q[i].x==q[p].x){
            idx[i]=k;
        }
        else break;
        cnt2++;
    }
    printf("%lld\n",sum);
    for(int i=0;i<=p+cnt2;i++){
        cout<<idx[i]<<" "<<q[i].s<<" "<<q[i].x<<endl;
    }
    return 0;
}

当时想的是用idx[i]记录i的名次,然后先一直算到名次为k的i,后面再加上分数与名次为k的相同的

问题一:尽量不要在循环的括号里写;;,尽量有个范围,虽然后面满足某条件时可以break,但是如果没有考虑周全,漏掉了某些情况,那么就会死循环

问题二:idx不一定能等于k,如找名次前二的,90 90 80 名次为1 1 3,就没有名次二

总之漏洞很多

赛后进行一个修改:算名次的那个循环就专门算名次,把n个数的名次都算出来,不做其它事情

另外一个循环,就算名次小于等于k的有几个

这样,分工明确,思路清晰

一个循环只做一件事情,不容易出错

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=10010;
LL n,m,k;
struct Stu{
    string s;
    int x;
    bool operator<(const Stu &W)const{
        if(x!=W.x) return x>W.x;
        return s<W.s;
    }
}q[N];
int idx[N];
LL sum;
int p;
int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<n;i++){
        cin>>q[i].s>>q[i].x;
        if(q[i].x>=60&&q[i].x<m) sum+=20;
        if(q[i].x>=m&&q[i].x<=100) sum+=50;
    }
    sort(q,q+n);
    idx[0]=1;
    LL cnt=1;
    for(int i=1;i<n;i++){
        cnt++;
        if(q[i].x==q[i-1].x) idx[i]=idx[i-1];
        else idx[i]=cnt;
    }
    int p=0;
    for(int i=0;i<n;i++){
        p++;
        if(idx[i]>k&&idx[i-1]<=k){
            break;
        }
    }
    printf("%lld\n",sum);
    for(int i=0;i<p-1;i++){
        cout<<idx[i]<<" "<<q[i].s<<" "<<q[i].x<<endl;
    }
    return 0;
}

2.乘法口诀 

T322026 乘法口诀 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 

 比赛代码(20分拿了14分)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1010;
int a[N];
int n;
int main()
{
    int cnt=2;
    cin>>a[1]>>a[2];
    cin>>n;
    int cnt3=cnt;
//    printf("%d %d %d\n",a[1],a[2],a[3]);
    while(cnt3<=n){
        int x=a[cnt]*a[cnt-1];
//        printf("%d\n",x);
        int cnt1=0;
        int t=x;
        while(t){
            t/=10;
            cnt1++;
        }
//        printf("%d\n",cnt1);
        int cnt2=cnt1;
//        printf("%d ",cnt2);
        while(x){
            int y=x%10;
            a[cnt3+cnt2]=y;
//            printf("%d %d \n",cnt+cnt2,y);
            cnt2--;
            x/=10;
        }
        cnt3=cnt3+cnt1;
        cnt++;
    }
//    printf("%d %d %d\n",a[1],a[2],a[3]);
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

加了很多注释是因为当时有点小错误,找不到,就输出数来检验,另外,用纸笔模拟全过程也不失为一种检验的好方法

问题一:题目中数列最后两个数相乘得到一个新数,最后两个指的是

1 2,2 3,3 4,4 5,以此类推,根据样例才搞懂题意

问题二:每一位都成为数列的一项,那么数列的每一项只能是0到9,所以相乘最多是两位数,也就是说只要讨论两种情况,相乘是一位数或者两位数,比赛中我用while计算有多少位,使得题目更复杂了

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1010;
int a[N];
int n;
int main()
{
    int cnt=2;
    cin>>a[1]>>a[2];
    cin>>n;
    int cnt1=cnt;
    while(cnt1<=n){
        int x=a[cnt]*a[cnt-1];
        if(x<10){
            a[++cnt1]=x;
        }
        else{
            int y=x%10;
            x/=10;
            a[++cnt1]=x;
            a[++cnt1]=y;
    }
    cnt++;
  }
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

3.双人成行中的小游戏 

T322070 双人成行中的小游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 

记录每一行每一列的反转次数,遍历所有灯泡,该灯泡所在行列反转次数之和为奇数则亮

题目中H*W<=5*1e6,这样的话不知道行列具体数,可能行5*1e6,列为1,也可能行为1,列为5*1e6,这样定义二维数组都不好定义,要么用动态数组

但是反转的话,转过去又转回来,往返,那么就与奇数次偶数次有关了

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=5e6+10;
int a[N],b[N];//a[i]记录i行反转的次数,b[j]记录j列反转的次数
int main()
{
    int h,w,k;
    cin>>h>>w>>k;
    while(k--){
        int n,m;
        cin>>n>>m;
        if(n==1){
            a[m]++;
        }
        else b[m]++;
    }
    LL res=0;
    for(int i=1;i<=h;i++){
        for(int j=1;j<=w;j++){
            if((a[i]+b[j])%2==1) res++;
        }
    }
    cout<<res<<endl;
    return 0;
}

4.顶级理解 

 

 

错误代码(25分拿了8分): 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int a[N];
int sum;
int main()
{
    int u,v,n;
    cin>>u>>v>>n;
    int cnt=1;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        sum+=a[i];
        if(sum-u>=0){
            cout<<"Yes "<<v<<endl;
            break;
        }
        if(sum/100==cnt&&i>=3){
            v-=(a[i]+a[i-1]+a[i-2]);
            cnt++;
        }
        if(sum/100==cnt&&i==2){
            v-=(a[2]+a[1]);
            cnt++;
        }
        if(v<=0){
        cout<<"gg "<<u-sum<<endl;
        break;
        }
    }
    if(v>0&&u-sum>0) cout<<"No "<<u-sum<<endl;
    return 0;
}

注意,boss会遗忘三次招式,也就意味这三次招式要出栈

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
const int N=1010;
int a[N];
int sum;
int main()
{
    int u,v,n;
    cin>>u>>v>>n;
    int cnt=1;
    stack<int>q;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        q.push(a[i]);
        sum+=a[i];
        if(sum-u>=0){
        cout<<"Yes "<<v<<endl;
         break;
        }
        if(sum/100==cnt){
            if(q.size()){
                v-=q.top();
                q.pop();
            }
            if(q.size()){
                v-=q.top();
                q.pop();
            }
            if(q.size()){
                v-=q.top();
                q.pop();
            }
            cnt++;
        }
        if(v<=0){
            cout<<"gg "<<u-sum<<endl;
            break;
        }
    }
    if(v>0&&u-sum>0) cout<<"No "<<u-sum<<endl;
    return 0;
}

5.wyb爱旅行 

 

思路:初看题目,想到最短路,但是题目多加了一个条件,就是在途中要打一次codeforces,这样的话,原本路径最短的加上了一次网费,就不一定是最小的了

做法是用两次最短路,求从1到其它点的最短路以及从n到其它点的最短路。枚举每个城市,从1到该城市的最短距离加上该城市到n的最短距离,再加上该城市的网费,取最小的

错误代码(只对了一个样例):

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef long long LL;
const int N=100010,M=2*N;
int p[N];
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int dist[N],d[N];
bool st[N],s[N];
void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
}
void dijkstra1(){
memset(d,0x3f,sizeof d);
d[n]=0;
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,n});
while(q.size()){
auto t=q.top();
q.pop();
int ver=t.second,distance=t.first;
if(s[ver]) continue;
s[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(d[j]>distance+w[i]){
d[j]=distance+w[i];
q.push({d[j],j});
}
}
}
}
int main()
{
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++) cin>>p[i];
    cin>>m;
    while(m--){
        int u,v,c;
        cin>>u>>v>>c;
        add(u,v,c);
        add(v,u,c);
    }
    dijkstra();
    dijkstra1();
    int min1=dist[1]+d[1]+p[1];
    for(int i=2;i<=n;i++){
        min1=min(min1,dist[i]+d[i]+p[i]);
    }
    cout<<min1<<endl;
    return 0;
}

错误原因是要建两个图,直接改无向边可能会有更短的路出现 

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef long long LL;
const int N=100010,M=2*N;
int p[N];
int n,m;
int h[N],e[M],w[M],ne[M],idx;
int h1[N],e1[M],w1[M],ne1[M],idx1;
int dist[N],d[N];
bool st[N],s[N];
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void add1(int a,int b,int c){
e1[idx1]=b,w1[idx1]=c,ne1[idx1]=h1[a],h1[a]=idx1++;
}
void dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>distance+w[i]){
dist[j]=distance+w[i];
heap.push({dist[j],j});
}
}
}
}
void dijkstra1(){
memset(d,0x3f,sizeof d);
d[n]=0;
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,n});
while(q.size()){
auto t=q.top();
q.pop();
int ver=t.second,distance=t.first;
if(s[ver]) continue;
s[ver]=true;
for(int i=h1[ver];i!=-1;i=ne1[i]){
int j=e1[i];
if(d[j]>distance+w1[i]){
d[j]=distance+w1[i];
q.push({d[j],j});
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
memset(h1,-1,sizeof h1);
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i];
cin>>m;
while(m--){
int u,v,c;
cin>>u>>v>>c;
add(u,v,c);
add1(v,u,c);
}
dijkstra();
dijkstra1();
int min1=dist[1]+d[1]+p[1];
for(int i=2;i<=n;i++){
min1=min(min1,dist[i]+d[i]+p[i]);
}
cout<<min1<<endl;
return 0;
}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值