PAT(甲級)2020年冬季考試自測


自測時間為2021年春季考試前一天下午\(5:00 \sim 8:00\)

7-1 The Closest Fibonacci Number (20 分)

The Fibonacci sequence $F_n$ is defined by $F_{n+2} = F_{n+1} + F_n$ for $n \ge 0$, with $F_0$ and $F_1=1$. The closet Fibonacci number is defined as the Fibonacci number with the smallest absolute difference with the given integer $N$.

Your job is to find the closest Fibonacci number for any given $N$.

Input Specification:

Each input file contains one test case, which gives a positive integer $N (≤10^8)$.

Output Specification:

For each case, print the closest Fibonacci number. If the solution is not unique, output the smallest one.

Sample Input:

305

Sample Output:

233

Hint:

Since part of the sequence is ${ 0, 1, 1, 2, 3, 5, 8, 12, 21, 34, 55, 89, 144, 233, 377, 610, … }$, there are two solutions: $233$ and $377$, both have the smallest distance $72$ to $305$. The smaller one must be printed out.

Solution

簽到題不多說了。

#include<iostream>
using namespace std;

const int INF=0x3f3f3f3f;
const int N=10010;
int f[110];
int n;
int cnt;

void init(int maxn)
{
    f[0]=0,f[1]=1;
    cnt=2;
    for(int i=2;;i++)
    {
        f[i]=f[i-1]+f[i-2];
        cnt++;
        if(f[i] > maxn) break;
    }
}

int main()
{
    cin>>n;
    init(n);

    int res=INF;
    for(int i=0;i<cnt;i++)
        if(abs(f[i]-n) < abs(res-n))
            res=f[i];
    cout<<res<<endl;
    //system("pause");
    return 0;
}

7-2 Subsequence in Substring (25 分)

A substring is a continuous part of a string. A subsequence is the part of a string that might be continuous or not but the order of the elements is maintained. For example, given the string atpaaabpabtt, pabt is a substring, while pat is a subsequence.

Now given a string $S$ and a subsequence $P$, you are supposed to find the shortest substring of $S$ that contains $P$. If such a solution is not unique, output the left most one.

Input Specification:

Each input file contains one test case which consists of two lines. The first line contains S and the second line P. S is non-empty and consists of no more than $10^4$ lower English letters. $P$ is guaranteed to be a non-empty subsequence of $S$.

Output Specification:

For each case, print the shortest substring of $S$ that contains $P$. If such a solution is not unique, output the left most one.

Sample Input:

atpaaabpabttpcat
pat

Sample Output:

pabt

Solution

寫了將近\(45\)分鍾的一個題,浪費了許多時間,先寫了個二分,拿了\(20\)分,后來想了個雙指針做法,拿了滿分。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;

const int INF=0x3f3f3f3f;
const int N=10010;
string s,p;
bool vis[N];
vector<int> posl;

bool check(int st,int len)
{
    int j=0;
    for(int i=st;i<st+len;i++)
    {
        if(s[i] == p[j]) j++;
        if(j == p.size()) return true;
    }
    return false;
}

int main()
{
    cin>>s>>p;

    for(int i=0;i<s.size();i++)
        if(s[i] == p[0])
            posl.pb(i);
    posl.pb(s.size());

    int l=posl[0],k=0;
    int cnt=1;
    string ans;
    while(l<s.size())
    {
        int r=l;
        while(r < s.size() && !vis[k])
        {
            if(s[r] == p[k])
            {
                vis[k]=true;
                k++;
            }
            if(k == p.size()) break;
            r++;
        }

        //cout<<l<<' '<<r<<endl;
        if(k == p.size())
            if(ans.size() == 0 || r-l+1 < ans.size())
                ans=s.substr(l,r-l+1);
        l=posl[cnt++];
        memset(vis,0,sizeof vis);
        k=0;
    }
    cout<<ans<<endl;
    //system("pause");
    return 0;
}

7-3 File Path (25 分)

1cb58ce0-f614-4616-b2a2-f18fc3f4fa34.JPG
The figure shows the tree view of directories in Windows File Explorer. When a file is selected, there is a file path shown in the above navigation bar. Now given a tree view of directories, your job is to print the file path for any selected file.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer $N (≤10^3)$, which is the total number of directories and files. Then $N$ lines follow, each gives the unique $4$-digit ID of a file or a directory, starting from the unique root ID 0000. The format is that the files of depth d will have their IDs indented by d spaces. It is guaranteed that there is no conflict in this tree structure.

Then a positive integer $K (≤100)$ is given, followed by $K$ queries of IDs.

Output Specification:

For each queried ID, print in a line the corresponding path from the root to the file in the format: 0000->ID1->ID2->...->ID. If the ID is not in the tree, print Error: ID is not found. instead.

Sample Input:

14
0000
 1234
  2234
   3234
    4234
    4235
    2333
   5234
   6234
    7234
     9999
  0001
   8234
 0002
4 9999 8234 0002 6666

Sample Output:

0000->1234->2234->6234->7234->9999
0000->1234->0001->8234
0000->0002
Error: 6666 is not found.

Solution

這題總的來說還好,花了大概\(30\)分鍾的樣子,一開始覺得挺難寫的,但其實算個不是很復雜的小模擬吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<unordered_set>
#define pb push_back
using namespace std;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int N=10010;
int dir[N];
int fa[N];
int dep[N];
unordered_set<int> S;
int n,m;

void print(int x)
{
    if(fa[x] == -1)
    {
        printf("%04d",x);
        return;
    }
    print(fa[x]);
    printf("->%04d",x);
}

int main()
{
    memset(fa,-1,sizeof fa);
    cin>>n;
    cin.ignore();

    int last=0;
    for(int i=0;i<n;i++)
    {
        string s;
        getline(cin,s);
        int k=0;
        for(int i=0;i<s.size();i++)
        {
            if(isdigit(s[i])) break;
            else k++;
        }

        int t=stoi(s.substr(k));
        S.insert(t);
        dep[t]=k;

        if(k == dep[last]+1)
            fa[t]=last;
        else if(k)
            fa[t]=dir[k-1];

        dir[k]=t;

        last=t;
    }

    cin>>m;
    while(m--)
    {
        int x;
        cin>>x;
        if(S.count(x) == 0)
            printf("Error: %04d is not found.",x);
        else
            print(x);
        cout<<endl;
    }
    //system("pause");
    return 0;
}

7-4 Chemical Equation (30 分)

A chemical equation is the symbolic representation of a chemical reaction in the form of symbols and formulae, wherein the reactant entities are given on the left-hand side and the product entities on the right-hand side. For example, $CH_4 + 2O_2 =CO_2 +2H_2O$ means that the reactants in this chemical reaction are methane and oxygen: $CH_4$ and $O_2$, and the products of this reaction are carbon dioxide and water: $CO_2$ and $H_2O$.

Given a set of reactants and products, you are supposed to tell that in which way we can obtain these products, provided that each reactant can be used only once. For the sake of simplicity, we will consider all the entities on the right-hand side of the equation as one single product.

Input Specification:

Each input file contains one test case. For each case, the first line gives an integer $N (2≤N≤20)$, followed by N distinct indices of reactants. The second line gives an integer $M (1≤M≤10)$, followed by M distinct indices of products. The index of an entity is a $2$-digit number.

Then a positive integer $K (≤50)$ is given, followed by $K$ lines of equations, in the format:

reactant_1 + reactant_2 + ... + reactant_n -> product

where all the reactants are distinct and are in increasing order of their indices.

Note: It is guaranteed that

  1. one set of reactants will not produce two or more different products, i.e. situation like 01 + 02 -> 03 and 01 + 02 -> 04 is impossible;
  2. a reactant cannot be its product unless it is the only one on the left-hand side, i.e. 01 -> 01 is always true (no matter the equation is given or not), but 01 + 02 -> 01 is impossible; and
  3. there are never more than $5$ different ways of obtaining a product given in the equations list.

Output Specification:

For each case, print the equations that use the given reactants to obtain all the given products. Note that each reactant can be used only once.

Each equation occupies a line, in the same format as we see in the inputs. The equations must be print in the same order as the products given in the input. For each product in order, if the solution is not unique, always print the one with the smallest sequence of reactants – A sequence {${ a_1,⋯,a_m}$} is said to be smaller than another sequence {${b_1,⋯,b_n}$} if there exists $1≤i≤min(m,n)$ so that $a_j = b_j$ for all $j<i$, and $a_i<b_i$.

It is guaranteed that at least one solution exists.

Sample Input:

8 09 05 03 04 02 01 16 10
3 08 03 04
6
03 + 09 -> 08
02 + 08 -> 04
02 + 04 -> 03
01 + 05 -> 03
01 + 09 + 16 -> 03
02 + 03 + 05 -> 08

Sample Output:

02 + 03 + 05 -> 08
01 + 09 + 16 -> 03
04 -> 04

Solution

額,寫這題之前跑去吃了個晚飯,這題的實際花費時間大概不到一小時的樣子。

先是讀題,讀完一直在想是不是啥特殊性質題,后來想PAT應該不會考那些高深的東西吧,直接暴搜了,其實暴搜想想的話效率應該還行的,畢竟如果選定一組反應物的話會剪掉很多分支。

考試結束前\(10 \sim 15\)分鍾寫完加調完,交上去\(28\)分,有點吃驚,然后結束前\(5\)分鍾也不知道哪個case沒考慮到,就等它結束了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<unordered_set>
#define pb push_back
using namespace std;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
const int N=25;
int a[N],b[N];
int n,m,k;
vector<vector<int>> mp[110];
vector<vector<int>> ans;
vector<vector<int>> path;
unordered_set<int> S;
bool vis[110];

void dfs(int u)
{
    if(u == m)
    {
        if(ans.size() == 0 || path < ans) ans=path;
        return;
    }

    for(int i=0;i<mp[b[u]].size();i++)
    {
        //cout<<u<<' '<<mp[b[u]][i].size()<<endl;
        bool ok=true;
        for(int j=0;j<mp[b[u]][i].size();j++)
        {
            int t=mp[b[u]][i][j];
            //cout<<"---"<<t<<endl;
            if(vis[t])
            {
                ok=false;
                break;
            }
        }

        if(ok)
        {
            for(int j=0;j<mp[b[u]][i].size();j++)
            {
                int t=mp[b[u]][i][j];
                vis[t]=true;
            }
            path.pb(mp[b[u]][i]);
            dfs(u+1);
            path.pop_back();
            for(int j=0;j<mp[b[u]][i].size();j++)
            {
                int t=mp[b[u]][i][j];
                vis[t]=false;
            }
        }
    }
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i],S.insert(a[i]);

    cin>>m;
    for(int i=0;i<m;i++) cin>>b[i];

    cin>>k;
    cin.ignore();
    for(int i=0;i<k;i++)
    {
        string s;
        getline(cin,s);
        vector<int> reactant;
        string num;
        bool ok=true;
        for(int i=0;i<s.size()-2;i++)
        {
            if(isdigit(s[i]))
            {
                num+=s[i];
            }
            else if(num.size())
            {
                if(S.count(stoi(num)) == 0)//左側不是反應物,那么就是不合法的方程式
                {
                    ok=false;
                    break;
                }
                reactant.pb(stoi(num));
                num.clear();
            }
        }

        int product=stoi(s.substr(s.size()-2));
        if(ok) mp[product].pb(reactant);
    }

    for(int i=0;i<m;i++)
    {
        vector<int> reactant;
        if(S.count(b[i]))
        {
            reactant.pb(b[i]);
            mp[b[i]].pb(reactant);
        }
    }

    dfs(0);

    for(int i=0;i<ans.size();i++)
    {
        for(int j=0;j<ans[i].size();j++)
        {
            int t=ans[i][j];
            if(j) printf(" + %02d",t);
            else printf("%02d",t);
        }
        printf(" -> %02d",b[i]);
        puts("");
    }

    //system("pause");
    return 0;
}

結束后發現沒考慮左側反應物為產物的情況,又發現樣例中已經提示了這種情況,啊這,屬實可惜。

總結

簡單題不能出岔子啊,第一題大概10分鍾以內解決,第二三題加起來最好不超過一個小時,剩下的兩個小時留給最后一題。優先想暴力,比如上面的第二題結束后發現暴力也可以過。

string s,p;

int main()
{
    cin>>s>>p;

    string ans;
    for(int i=0;i<s.size();i++)
        if(s[i] == p[0])
        {
            string t;
            int k=0;
            for(int j=i;j<s.size();j++)
            {
                if(s[j] == p[k]) k++;
                if(k == p.size())
                {
                    t=s.substr(i,j-i+1);
                    break;
                }
            }
            if(ans.size() == 0 || t.size() && t.size() < ans.size()) ans=t;
        }

    cout<<ans<<endl;
    //system("pause");
    return 0;
}

注意要判斷子串\(t\)是否為空串,若為空串則不是有效子串。

\(update\)
春季考了\(98\)分,原來考前一晚的分數已經暗示了結局(草)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM