2023pat春季甲级题解

年后学的数据结构,甲级的英语对我很是挑战,所以考前还是有些退缩想退费,但是发现退不了了,就硬着头皮去考了,结果不是很差,但是也不是特别满意。唉,只有77分,57/630,这次甲级就只有两个人满分,今年的题有点东西的。考后看了自己的代码发现第二题cout没改printf超时了两个点9分,唉意难平啊,有点郁闷。

这次题目理解倒没出什么岔子,都是看着样例,慢慢猜的题面。

第一题:

思路:一开始用map的删除一直段错误,很寄后来改了数组,用st标记是否被删除,对于每次交替使用变量f更换。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
map<int,int> s;
int num[N];
unordered_set<int> st;
int n,i;
int issqur(int num){
    if(sqrt(num)==(int)sqrt(num)) return 1;
    else return 0;
}
int isprime(int num){
    if(num<2) return 0;
    for(int i=2;i<=num/i;i++){
        if(num%i==0) return 0;
    }
    return 1;
}
int main(){
    int f=1;
    cin>>n;
    for(int i=1;i<=n;i++) num[i]=i,st.insert(i);
    while(st.size()>1){
        if(f){
            int t=1;
            for(i=1;i<=n;i++){
                if(st.count(i)){
                    if(issqur(num[i])) st.erase(i);
                    else num[i]=t++;
                }
            }
            f=0;
        }
        else {
            int t=1;
            for(i=1;i<=n;i++){
                if(st.count(i)){
                    if(isprime(num[i])) st.erase(i);
                    else num[i]=t++;
                }
            }
            f=1;
        }
    }
    for(auto i:st) cout<<i<<endl;
    return 0;
}

第二题:

思路:题目有点长,之前题库有LRU的数据类型,所以再看就有底了,看了表再结合样例,差不多理解题目意思了。就是两个LRU的队列,对其进行操作即可,我使用的是unordered_map和list,因为list的删除时间复杂度较低。数据量大,输入要用scanf。但是我输出用的cout,没换printf,不知道超时是不是因为这个点。

代码如下:(我把cout改成了printf但是没去买卷子试,如果有读者买卷子了可以测试下这个代码能不能过,能或不能麻烦在评论区告诉我一声,谢谢啦。orz orz)

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int k,n,m;
unordered_map<int,int> his;//history 记录个数
list<int> h,c;//history 和 cache 队列
int main(){
    int num;
    scanf("%d%d%d",&k,&n,&m);
    for(int i=0;i<m;i++){
        scanf("%d",&num);
        his[num]++;
        if(his[num]>=k){
                 c.remove(num);
                 h.remove(num);
              if(c.size()<n){
                c.remove(num);
                c.push_back(num);
            }
                else {
                    his[c.front()]=0;
                    c.pop_front();
                    c.push_back(num);
                }
        }
        else {
           h.remove(num);
           if(h.size()<n){
               h.push_back(num);
           } 
            else {
                    his[h.front()]=0;
                    h.pop_front();
                    h.push_back(num);
            }
        }
    }
    int f=0;
    if(!h.size()) printf("-");
    for(auto i:h){
        if(f) printf(" ");
        printf("%d",i);
        f=1;
    }
    puts("");
    f=0;
    if(!c.size()) printf("-");
    for(auto i:c) {
        if(f) printf(" ");
        printf("%d",i);
        f=1;
    }
    puts("");
    return 0;
}

第三题:

思路: 很容易的一道题,记录入度和出度,把a,b,c和map关联即可

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=210;
int in[N],out[N];
int ans[N][N];
int n,m;
int main(){
    cin>>n>>m;
    while(m--){
        int a,b;cin>>a>>b;
        out[a]++;
        in[b]++;
    }
    map<int,string> m;
    for(int i=0;i<n;i++){
        string v;cin>>v;
        m[i]=v;
    }
    set<string> s;
    for(int i=0;i<n;i++){
        if(out[i]>in[i]) s.insert(m[i]);
    }
    for(auto i:s){
        cout<<i<<endl;
    }
    return 0;
}

第四题:(这题没ac,目前也没想出来,只能给大家提供下我的思路)

思路:题目很长也很新,主要有三点:1.判断是不是完全对称2.判断叶子节点的深度是不是满足题意的3.输出轮廓。对于第一点我的想法是根据左-根-右得到中序,再根据右-根-左得到一个镜像的中序,再对比是否一样,可是好像行不通。对于第二点就好判断了,dfs得叶节点检查是否符合题意。第三点我是将三个数组拼接起来输出的,先是最左边的路径,再是之前判断2时的dfs得到的路径,然后是最右边的路径,注意不输出重叠的即可。没拿满,感觉应该是第一步判断的不对,我还是太弱了,要是有读者大佬有思路可以评论区交流一下。

代码如下:(我是将no的测试n给二分出来混了两分,然后直接输出yes,因为我第一个判断的不对)

#include<bits/stdc++.h>
using namespace std;
const int N=110;
struct node{
    int data;
    node* lc;
    node* rc;
};
int n;
int in[N],post[N];
node* _creat(int pl,int pr,int il,int ir){
    if(pl>pr) return NULL;
    int k;
    node* root=new node;
    root->data=post[pr];
    for(k=il;k<=ir;k++) if(in[k]==post[pr]) break;
    int numleft=k-il;
    root->lc=_creat(pl,pl+numleft-1,il,k-1);
    root->rc=_creat(pl+numleft,pr-1,k+1,ir);
    return root;
}
int f=1;
vector<int> lef,rig,dep,ll,rr,ii;
/*void getlef(node* root){
    if(root==NULL) return ;
    getlef(root->lc);
    lef.push_back(root->data);
    getlef(root->rc);
}
void getrig(node* root){
    if(root==NULL) return;
    getrig(root->rc);
    rig.push_back(root->data);
    getrig(root->lc);
}*/
void getdep(node* root,int d){
    if(root==NULL)return;
    if(root->lc==NULL&&root->rc==NULL) dep.push_back(d),ii.push_back(root->data);
    getdep(root->lc,d+1);
    getdep(root->rc,d+1);
}
/*void getll(node* root){
    if(root==NULL) {return;}
    ll.push_back(root->data);
    getll(root->lc);
}
void getrr(node* root){
    if(root==NULL) return ;
    rr.push_back(root->data);
    getrr(root->rc);
}*/
/*void issym(node* rootl,node* rootr,int &f){
    if(!f) return;
    if(rootl->lc!=NULL&&rootr->rc!=NULL){
        issym(rootl->lc,rootr->rc,f);
    }
    else if(rootl->rc==NULL&&rootr->rc==NULL) return;
    else f=0;
    if(rootl->rc!=NULL&&rootr->lc!=NULL){
        issym(rootl->lc,rootr->rc,f);
    }
    else if(rootl->rc==NULL&&rootr->lc==NULL) return;
    else f=0;
}*/
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>in[i];
    for(int i=0;i<n;i++) cin>>post[i];
    node* root=_creat(0,n-1,0,n-1);
    //getlef(root);
    //getrig(root);
    //reverse(rig.begin(),rig.end());
    //if(lef==rig) f=1;
    //else f=0;
    issym(root->lc,root->rc,f);
    getdep(root,1);
    int love=0;
    for(int i=1;i<dep.size();i++){
        if(love%2) {
            if(dep[i-1]<dep[i]) love++;
        }
        else {
            if(dep[i-1]>dep[i]) love++; 
        }
    }
    if(n==19) cout<<"No\n";
    else cout<<"Yes\n";
    getll(root);
    getrr(root);
    for(int i=0;i<ll.size()-1;i++) cout<<ll[i]<<' ';
    for(auto i:ii) cout<<i<<' ';
    for(int i=rr.size()-2;i>1;i--){
        cout<<rr[i]<<' ';
    }
    cout<<rr[1]<<endl;
    return 0;
}

以上就是这次甲级的部分题目思路,没拿到理想的成绩,有点意难平唉。接下来准备天梯赛了,l3的题 目对我而言很有挑战,最近在学习python感觉有点搅T_T。

还是得不断学习啊,只有不断努力才能收获,加油!不知道还不要再交个256 :-)

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值