2022夏季PAT甲级——AK记录

T1

题目大意
给出两个人对于 “ 昨天、今天、明天 ” 的描述,其中,每个人仅提供一个正确信息。确定 “ 今天 ” 到底是星期几,并给出两人的正确信息是哪个维度。

考场上用了比较笨的方法:枚举每个人的正确信息
十五分钟AC

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

char day[7][20]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
char ans[3][20]={"yesterday","today","tomorrow"};
int a[5];
int b[5];

int main()
{
    scanf("%d%d%d",&a[0],&a[1],&a[2]);
    scanf("%d%d%d",&b[0],&b[1],&b[2]);
    if (a[0]==b[0]) {  //yes
        printf("%s\n",day[(a[0]+1)%7]);
        printf("%s\n%s",ans[0],ans[0]);
    }
    else if ((a[0]+1)%7==b[1]) {  //yes  to
        printf("%s\n",day[b[1]]);
        printf("%s\n%s",ans[0],ans[1]);
    }
    else if ((a[0]+2)%7==b[2]) {  //yes mo
        printf("%s\n",day[(a[0]+1)%7]);
        printf("%s\n%s",ans[0],ans[2]);
    }
    else if (a[1]==(b[0]+1)%7) {  //to yes
        printf("%s\n",day[a[1]]);
        printf("%s\n%s",ans[1],ans[0]);
    }
    else if (a[1]==b[1]) {  //to
        printf("%s\n",day[a[1]]);
        printf("%s\n%s",ans[1],ans[1]);
    }
    else if ((a[1]+1)%7==b[2]) {  //to mo
        printf("%s\n",day[a[1]]);
        printf("%s\n%s",ans[1],ans[2]);
    }
    else if (a[2]==(b[0]+2)%7) {  //mo yes
        printf("%s\n",day[(b[0]+1)%7]);
        printf("%s\n%s",ans[2],ans[0]);
    }
    else if (a[2]==(b[1]+1)%7) {  //mo to
        printf("%s\n",day[b[1]]);
        printf("%s\n%s",ans[2],ans[1]);
    }
    else if (a[2]==b[2]) {  //mo mo
        printf("%s\n",day[(a[2]-1+7)%7]);
        printf("%s\n%s",ans[2],ans[2]);
    }
    return 0;
}

T2

题目大意
模拟操作系统中的LRU机制,即最近最少使用(Least Recently Used),选择最近最久未使用的页面予以替换。

数据范围允许我投机取巧,使用一个队列记录cache中的页

  • 被访问页已经在内存中,则将该页移动到队首(原先的存储位置0表示失效)
  • 被访问页未在内存中,且内存未满,则直接调入被访问页
  • 被访问页未在内存中,但是内存已满,则选择最近最少使用页替换
    替换时,选取队尾的第一个有效页即可

二十分钟AC

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int N=10010;
const int M=100010;
int p[N*2]={0};
int Q[M*2];
int tou=0;
int wei=0;
int sz=0;
int ans[M];
int cnt=0;

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;++i) {
        int x;
        scanf("%d",&x);
        if (!p[x]) {   //not in cache
            if (sz<n) {
                ++sz;
                ++tou;
                p[x]=tou;
                Q[tou]=x;
            }            
            else {
                while (Q[wei]==0) wei++;
                ans[++cnt]=Q[wei];   //out
                p[Q[wei]]=0;
                ++wei;
                ++tou;
                p[x]=tou;
                Q[tou]=x;
            }
        }
        else {
            Q[p[x]]=0;
            ++tou;
            p[x]=tou;
            Q[tou]=x;
        }
    }
    for (int i=1;i<=cnt;++i) {
        printf("%d",ans[i]);
        if (i<cnt) printf(" ");
    }
    return 0;
}

T3

题目大意
给出一个有向图,询问某序列是否能够通过dfs该图得到。注意,每个节点仅被遍历一次,非连通图中可以有多个dfs起点。

可以通过dfs得到的序列:

  • x和y(序列中两个相邻的节点)之间存在边,且y之前未被访问过
  • x和y(序列中两个相邻的节点)之间不存在边,y之前未被访问过,且从x出发能够到达的所有结点均已遍历过,则y可以作为另一个dfs的起点

二十五分钟AC

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int N=1010;
const int M=10010;
int way[N][N]={0};
int n,m,k;
int a[N];
int init[N]={0};
int outit[N]={0};
int vis[N]={0};

int judge(int x,int y) {
    if (outit[x] == 0)  return 1;
    for (int i=1;i<=n;++i) {
        if (way[x][i] && !vis[i]) return 0;
    }    
    return 1;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;++i) {
        int u,v;
        scanf("%d%d",&u,&v);
        way[u][v]=1;
        init[v]++;
        outit[u]++;
    }
    for (int i=1;i<=k;++i) {
        int flag=1;
        for (int j=1;j<=n;++j) {
            scanf("%d",&a[j]);
            vis[j]=0;
        }
        vis[a[1]]=1;
        for (int j=2;j<=n;++j) {
            int x=a[j];
            if (vis[x]) {
                flag=0;
                break;
            }
            if (!way[a[j-1]][x] && !judge(a[j-1],x)) {
                flag=0;
                break;
            }
            vis[x]=1;
        }
        if (flag==0) {
            printf("no\n");
        }
        else {
            printf("yes\n");
        }
    }
    return 0;
}

T4

题目大意
有一棵完全d叉树,给出前序遍历,构造该树的层次遍历和父子关系。

按照层次遍历给每个节点编号后
完全二叉树存在这样的性质:对于任一节点 x x x 2 ∗ x 2*x 2x为其左儿子( 2 ∗ x < = n 2*x<=n 2x<=n), 2 ∗ x + 1 2*x+1 2x+1为其右儿子( 2 ∗ x + 1 < = n 2*x+1<=n 2x+1<=n
同理,完全d叉树存在类似性质:对于任一节点 x x x d ∗ x − ( d − 2 ) d*x-(d-2) dx(d2) d ∗ x + 1 d*x+1 dx+1为其所有的儿子(儿子的编号 < = n <=n <=n

前序遍历采取 “ 先根后儿子 ” 的遍历顺序
这就是赤裸裸的 “ 父子 ” 关系
我们可以根据之前得到的结论,对于每个节点重新赋予层次遍历的编号
从前往后扫描前序遍历,构造完全d叉树

思路比较精妙,可以直接看代码

三十分钟AC

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int N=60;
struct node{
    int fa;
    int num;
};
node T[N];
int n,d,k;
int pre[N];
int deep[N];
int cnt=0;

void build(int f,int id) {
    T[id].num=pre[++cnt];
    T[id].fa=f;
    for (int i=id*d-(d-2);i<=id*d+1;++i) {
        if (i<=n) {
            build(id,i);
        }
        else break;
    }
}

int main()
{
    scanf("%d%d",&n,&d);
    for (int i=1;i<=n;++i) {
        scanf("%d",&pre[i]);
    }
    build(0,1);
    for (int i=1;i<=n;++i) {
        printf("%d",T[i].num);
        if (i<n) printf(" ");
    }
    printf("\n");
    scanf("%d",&k);
    for (int i=1;i<=k;++i) {
        int x;
        scanf("%d",&x);
        x++;
        while (x!=0) {
            printf("%d",T[x].num);
            if (x!=1) printf(" ");
            else printf("\n");
            x=T[x].fa;
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值