PAT (Advanced Level) Practice 1084-1087 题解

1084 Broken Keyboard (20分)

On a broken keyboard, some of the keys are worn out. So when you type some sentences, the characters corresponding to those keys will not appear on screen.

Now given a string that you are supposed to type, and the string that you actually type out, please list those keys which are for sure worn out.

Input Specification:
Each input file contains one test case. For each case, the 1st line contains the original string, and the 2nd line contains the typed-out string. Each string contains no more than 80 characters which are either English letters [A-Z] (case insensitive), digital numbers [0-9], or _ (representing the space). It is guaranteed that both strings are non-empty.

Output Specification:
For each test case, print in one line the keys that are worn out, in the order of being detected. The English letters must be capitalized. Each worn out key must be printed once only. It is guaranteed that there is at least one worn out key.

Sample Input:
7_This_is_a_test
_hs_s_a_es
Sample Output:
7TI

题意

在一个破损的键盘上,有一些键发生了损坏,敲击损坏的键不会在屏幕显示,给出一组敲击键盘的命令A和一组显示在屏幕上的字符B,输出损坏的键(按照敲击的顺序输出)。

思路

通过一个数组来记录被敲击的键,遍历A,将出现的字符都++,之后遍历B,将遍历的字符都置零,再遍历一次A,如果出现字符的次数不为0,则为损坏的键,输出。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=85;
int num[256];
char a[maxn],b[maxn];
int isout[256];
int main()
{
    memset (num,0,sizeof(num));
    memset (isout,0,sizeof(isout));
    scanf("%s%s",a,b);
    int len1=strlen(a),len2=strlen(b);
    for (int i=0;i<len1;i++)
    {
        if(a[i]>='a'&&a[i]<='z')
            a[i]=a[i]-'a'+'A';
        num[a[i]]++;
    }
    for (int i=0;i<len2;i++)
    {
         if(b[i]>='a'&&b[i]<='z')
            b[i]=b[i]-'a'+'A';
        num[b[i]]=0;
    }
    for (int i=0;i<len1;i++)
    {
        if(num[a[i]])
        {
            printf("%c",a[i]);
            num[a[i]]=0;
        }
    }
        printf("\n");
    return 0;
}

Perfect Sequence (25 分)

Given a sequence of positive integers and another positive integer p. The sequence is said to be a perfect sequence if M≤m×p where M and m are the maximum and minimum numbers in the sequence, respectively.

Now given a sequence and a parameter p, you are supposed to find from the sequence as many numbers as possible to form a perfect subsequence.

Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers N and p, where N (≤10
​5
​​ ) is the number of integers in the sequence, and p (≤10
​9
​​ ) is the parameter. In the second line there are N positive integers, each is no greater than 10
​9
​​ .

Output Specification:
For each test case, print in one line the maximum number of integers that can be chosen to form a perfect subsequence.

题意

给出一个数组A,和一个数字p,求满足M<=m*p的序列的最大长度(m表示序列的最小值,M表示序列的最大值)。

思路

升序排序,之后从头遍历,找出满足小于等于a[i]*p的最大的数(二分查找)。算出序列的元素个数

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
ll a[maxn];
int n;
ll p;
vector<int>v;
//查找小于等于x的最大数
int binary_search(ll x)
{
    int st=0,en=n-1;
    int loc=-1;
    while(st<=en)
    {
        int mid=(st+en)/2;
        if(a[mid]==x) return mid;
        else if(a[mid]>x) en=mid-1;
        else
        {
            loc=mid;
            st=mid+1;
        }
    }
    return loc;
}
int main()
{
    scanf("%d%lld",&n,&p);
    for (int i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
    }
    if(n==1)
    {
        printf("1\n");
        return 0;
    }
    sort(a,a+n);
    int num=0;
    for (int i=0;i<n-1;i++)
    {
        ll re=a[i]*p;
        int loc=binary_search(re);
        //a[loc]必须比a[i]大
        if(loc>i&&re>=a[loc])
        {
            num=max(num,loc-i+1);
        }
    }
    printf("%d\n",num);
    return 0;
}

Tree Traversals Again

题意

An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.
在这里插入图片描述

Figure 1
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: “Push X” where X is the index of the node being pushed onto the stack; or “Pop” meaning to pop one node from the stack.

Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1

题意

给出一个栈中元素的进出顺序,求通过这个栈构造出的二叉树的后序遍历。

思路

通过观察可知,栈的入栈顺序其实是二叉树的前序遍历,栈的出栈顺序其实是二叉树的中序遍历。
那么,这个题目就可以转化为已知二叉树的前序和中序遍历求二叉树的后序遍历。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=35;
int n,num=0;
struct comm
{
    char s[10];
    int x;
};
struct tree
{
    int x;
    int left,right;
};
comm c[maxn*2];
tree t[maxn];
vector<int>pre,in,post;
//创建树
int create(int node,int pre_left,int pre_right,int in_left,int in_right)
{
    //int tnum=num;
    if(pre_right<pre_left) return -1;
    t[node].x=pre[pre_left];
    int k=-1;
    for (int i=in_left;i<=in_right;i++)
    {
        if(in[i]==pre[pre_left])
        {
            k=i;
            break;
        }
    }
    t[node].left=create(++num,pre_left+1,pre_left+k-in_left,in_left,k-1);
    t[node].right=create(++num,pre_left+k-in_left+1,pre_right,k+1,in_right);
    return node;
}
void post_traverse(int root)
{
    if(root==-1) return;
    post_traverse(t[root].left);
    post_traverse(t[root].right);
    post.push_back(t[root].x);
}
int main()
{
    memset (t,-1,sizeof(-1));
    scanf("%d",&n);
    stack<int>st;
    for (int i=0;i<2*n;i++)
    {
        char s[10];
        scanf("%s",s);
        if(s[1]=='u')
        {
            int x;
            scanf("%d",&x);
            pre.push_back(x);
            st.push(x);

        }
        else
        {
            int x=st.top();
            st.pop();
            in.push_back(x);
        }
    }
    int root=create(0,0,pre.size()-1,0,in.size()-1);
    post_traverse(0);
    for (int i=0;i<post.size();i++)
    {
        printf("%d%c",post[i],i==post.size()-1?'\n':' ');
    }
    return 0;
}

1087 All Roads Lead to Rome (30 分)

题意

给出一个图和起点城市和终点城市,图中有两点之间的距离和获得的快乐值,求起始到终点的最短距离,如果距离一样,则选用其中获得快乐最多的一条线路,如果获得的快乐相同,则选用其中经过城市最多的线路。

思路

迪杰斯特拉最短路算法的变式题,无非是加了几个判定,但是写起来还是挺麻烦的。
网上有些题解是先用迪杰斯特拉求出最短距离和线路,然后跑搜索,我感觉写起来还是挺麻烦的。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=205;
const int INF=0x3f3f3f3f;
int n,k;
map<string,int>ma;
string stc;
int num=0;
vector<string> name;
int hap[maxn];
int sumhap[maxn];
struct edge
{
    int to;
    int len;
};
int vis[maxn];
int dis[maxn];
int kind[maxn];
int pre[maxn];
int prenum[maxn];
vector<edge>e[maxn];
void djst()
{
    memset (vis,0,sizeof(vis));
    memset (kind,0,sizeof(kind));
    memset (sumhap,0,sizeof(sumhap));
    memset (pre,-1,sizeof(pre));
    fill(prenum,prenum+maxn,INF);
    for (int i=0;i<n;i++)
    {
        dis[i]=INF;
    }
    dis[0]=0;
    kind[0]=1;
    prenum[0]=0;
    while(1)
    {
        int Min=INF;
        int u=-1;
        for (int i=0;i<n;i++)
        {
            if(!vis[i]&&Min>dis[i])
            {
                u=i;
                Min=dis[i];
            }
        }
        if(u==-1) break;
        vis[u]=1;
        for (int i=0;i<e[u].size();i++)
        {
            int v=e[u][i].to;
            int len=e[u][i].len;
            if(!vis[v])
            {
                if(dis[v]>dis[u]+len)
                {
                    dis[v]=dis[u]+len;
                    kind[v]=kind[u];
                    sumhap[v]=sumhap[u]+hap[v];
                    pre[v]=u;
                    prenum[v]=prenum[u]+1;
                }
                else if(dis[v]==dis[u]+len)
                {
                    kind[v]+=kind[u];
                    if(sumhap[v]<sumhap[u]+hap[v])
                    {
                        sumhap[v]=sumhap[u]+hap[v];
                        pre[v]=u;
                        prenum[v]=prenum[u]+1;
                    }
                    else if(sumhap[v]==sumhap[u]+hap[v])
                    {
                        if(prenum[v]>prenum[u]+1)
                        {
                            pre[v]=u;
                            prenum[v]=prenum[u]+1;
                        }
                    }
 
                }
            }
        }
    }
}
int main()
{
    cin>>n>>k;
    cin>>stc;
    ma[stc]=num++;
    name.push_back(stc);
    hap[0]=0;
    for (int i=1;i<n;i++)
    {
        string s;
        cin>>s>>hap[i];
        ma[s]=num++;
        name.push_back(s);
    }
    for (int i=0;i<k;i++)
    {
        string a,b;
        int len;
        edge e1,e2;
        cin>>a>>b>>len;
        e1.to=ma[b];e1.len=len;
        e2.to=ma[a];e2.len=len;
        e[ma[a]].push_back(e1);
        e[ma[b]].push_back(e2);
    }
    djst();
    int no=ma["ROM"];
    printf("%d %d %d %d\n",kind[no],dis[no],sumhap[no],sumhap[no]/prenum[no]);
    int temp=no;
    stack<int>st;
    while(temp!=-1)
    {
        //printf("temp=%d\n",temp);
        st.push(temp);
        temp=pre[temp];
    }
 
    while(!st.empty())
    {
        int t=st.top();
        st.pop();
        cout<<name[t];
        if(!st.empty()) printf("->");
        else printf("\n");
    }
    return 0;
}

总结

这一套题感觉还是挺有难度的,想要3个小时AC确实是有难度的,感觉PTA甲级之前的题偏难,感觉这几年有点降低难度的势头。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章