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甲級之前的題偏難,感覺這幾年有點降低難度的勢頭。

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