PAT甲级思路测试点分析及提示(1001-1159更新中,二刷附代码中)

PAT甲级汇总,附测试点分析

文章目录


每道题我会根据我的错误或难点选择性记录,题目思路,在题目难懂的情况下写出题目大意,在测试点难以通过的情况下写出测试点的问题。
更新!!!
开始二刷,结果leetcode和acwing课程的帮助,希望可以降维打击,花十天选择性二刷,本次二刷将贴代码。

开始!

记录各种数据结构算法题型模版:

https://blog.csdn.net/emmmnmm/article/details/123971045
考到的模版有(加粗为常见):hash,dfs 1103题,bfs,最短路径,最小生成树,二分法,并查集,双指针,模拟栈,前缀和,位运算,堆,质数,约数,最大公约数。
其它题型:
给两种排序问哪一种,并执行一步
动态规划
结构体排序
不同顺序遍历树的转换1119题
树状数组1057题
AVL树1066,1123题
背包问题1068题
堆排序1098、1155、1147题
hash查找 1145题

1001 A+B Format (20分):

用自带函数进行int与string转化,这样可能代码短一些,最后在string中插入“,”,翻转一下即可。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int x,y,r,cnt;
string a,b,str;
int main(){
    cin>>a>>b;
    x=atoi(a.c_str());
    y=atoi(b.c_str());
    r=x+y;
    string str=to_string(r),result="";
    int size=str.size();
    for(int i=size-1;i>=0;i--){
        result+=str[i];
        cnt++;
        if(cnt%3==0&&cnt!=0&&cnt<size-1||(cnt%3==0&&cnt==size-1&&str[0]!='-')){
            result+=",";
        }
    }
    reverse(result.begin(),result.end());
    cout<<result<<endl;
}
1002 A+B for Polynomials (25分):

直接用map存,用到了反向遍历,迭代器可以直接auto,如果全称是map<int,double>::reverse_iterator,后几个测试点是两项相消,最后一个测试点是消光,0会格式错误

#include <iostream>
#include <map>
using namespace std;
int n,m,j=2;
double k;
map<int,double> h;
int main(){
    while(j--){
        scanf("%d",&n);
        while(n--){
            scanf("%d %lf",&m,&k);
            h[m]+=k;
            if(!h[m])
                h.erase(m);
        }
    }
    if(!h.size()){
        printf("0");
        return 0;
    }
    printf("%d ",h.size());
    for(auto it=h.rbegin();it!=h.rend();it++){
        if(it!=h.rbegin()) printf(" ");
        printf("%d %.1lf",it->first,it->second);
    }printf("\n");
}
1003 Emergency (25分):

一刷:
思路:迪杰斯特拉(Dijkstra)算法,注意两个点:

  1. 题目要求输出的是最短距离的不同路线的数量;
  2. 目标点不同可能性=原本可能性+新路径前一个点的可能性数量;
    第二点给出一个反例,这里0-2两种可能,0-3有1+2种可能。
    4 5 0 3
    1 2 1 5
    0 1 1
    0 2 2
    0 3 4
    1 2 1
    2 3 2
    二刷:模版题
#include <iostream>
#include <cstring>
using namespace std;
const int N=505;
int n,m,start,e,g[N][N],dist[N],p[N],people[N],st[N],path[N];//稠密图,邻接矩阵g存储边,p记录初始救援队,people记录出发后城市最大救援队,st标记数组,path记录路径数
void dijkstra(){
    dist[start]=0;
    people[start]=p[start];
    path[start]=1;
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=0;j<n;j++){
            if(!st[j]&&(dist[t]>dist[j]||t==-1))
                t=j;
        }
        st[t]=1;
        for(int j=0;j<n;j++){
            if(dist[j]>=dist[t]+g[t][j]&&g[t][j]!=0x3f3f3f3f){
                if(dist[j]==dist[t]+g[t][j]){
                    people[j]=max(people[t]+p[j],people[j]);
                    path[j]+=path[t];
                }else{
                    path[j]=path[t];
                    dist[j]=dist[t]+g[t][j];
                    people[j]=people[t]+p[j];
                }
            }
        }
    }
}
int main(){
    memset(dist,0x3f,sizeof dist);
    memset(g,0x3f,sizeof g);
    scanf("%d %d %d %d",&n,&m,&start,&e);
    for(int i=0;i<n;i++){
        scanf("%d",&p[i]);
    }
    while(m--){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        g[a][b]=g[b][a]=min(g[a][b],c);
    }
    dijkstra();
    printf("%d %d\n",path[e],people[e]);
}
1004 Counting Leaves (30分):

邻接矩阵存储+广度优先搜索模版题,二刷一遍过!!

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N=105;
int n,m,h[N],e[N],ne[N],idx,level=0,cnt;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(){
    queue<pair<int,int>> q;
    q.push({1,0});
    while(q.size()){
        auto t=q.front();
        q.pop();
        if(level!=t.second){
            printf("%d ",cnt);
            cnt=0;
            level++;
        }
        int c=0;
        for(int i=h[t.first];i!=-1;i=ne[i]){
            int j=e[i];
            q.push({j,t.second+1});
            c++;
        }
        if(!c)
            cnt++;
    }
    printf("%d\n",cnt);
}
int main(){
    scanf("%d %d",&n,&m);
    memset(h,-1,sizeof h);
    while(m--){
        int a,k,b;
        scanf("%d %d",&a,&k);
        while(k--){
            scanf("%d",&b);
            add(a,b);
        }
    }
    dfs();
}
1005 Spell It Right (20分):

注意0-9拼写错误;
注意输入0的问题:测试点2错误;
二刷一遍过

#include <iostream>
#include <string>
using namespace std;
string str;
int res;
string number[10]={"zero","one","two","three","four","five","six","seven","eight","nine"};
int main(){
    cin>>str;
    for(int i=0;i<str.size();i++){
        res+=str[i]-'0';
    }
    str=to_string(res);
    for(int i=0;i<str.size();i++){
        cout<<number[str[i]-'0'];
        if(i!=str.size()-1)
            cout<<" ";
        else
            cout<<"\n";
    }
}
1006 Sign In and Sign Out (25分):

用两个pair绑定时间和人,自动sort,代码巨短

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<pair<string,string>> e;
vector<pair<string,string>> l;
int main(){
    cin>>n;
    while(n--){
        string a,b,c;
        cin>>a>>b>>c;
        e.push_back({b,a});
        l.push_back({c,a});
    }
    sort(e.begin(),e.end());
    sort(l.begin(),l.end());
    cout<<e[0].second<<" "<<l[e.size()-1].second<<endl;
}
1007 Maximum Subsequence Sum (25分):

思路:动态规划,主要问题是测试点5, 6的0的问题,猜测:
第五个测试点样本是:-1 -2 -3 -4 全负数
第六个测试点样本是:-1 -2 -3 -4 0 0 0 -6 -7 这个样子

#include <iostream>
#include <limits.h>
using namespace std;
const int N=10010;
int n,g[N],h=-1,res=INT_MIN,s,e;
int main(){
    scanf("%d",&n);
    bool flag=false;
    for(int i=0;i<n;i++){
        scanf("%d",&g[i]);
        if(g[i]>=0) flag=true;
    }
    if(!flag){
        printf("%d %d %d\n",0,g[0],g[n-1]);
        return 0;
    }
    int start;
    for(int i=0;i<n;i++){
        if(h<0){
            h=g[i];
            start=g[i];
        }else{
            h+=g[i];
        }
        if(h>res){
            res=h;
            s=start;
            e=g[i];
        }
    }
    printf("%d %d %d\n",res,s,e);
}
1008 Elevator (20分):

有点简单;

1009 Product of Polynomials (25分):

思路:和1002类似,用标记数组,已知第一个测试点考察是否忽略了两个指数为0的项相乘;

1010 Radix (25分):
  1. 首先需要考虑radix上限可能很大需要用long long类型;
  2. 其次要确定radix的值不能一点点递增上去,需要使用二分法,若非二分法测试点7会超时;
  3. 用了二分法需要注意low与high初始值问题,举个栗子:2 2 1 10
    此时low=3>high=2,边界条件为while(low<=high)时直接impossble了,第一个测试点不能通过,注意取high=max(low,另一个数字十进制值);
  4. 即使用了long long类型依然要考虑上溢的情况。如zzzz zzzz 1 60,即虽然zzzz(60)不会上溢,但假设的进制数zzzz(radix)会导致上溢。增加一个判定条件在数值<0时,同样使high=mid-1;
  5. 还有一个反例:0 0 1 10,虽然题目没有考察,可能对于有没有一进制存在争议吧;
#include <iostream>
#include <algorithm>
using namespace std;
string n1,n2;
int tag;
long long n,radix;

long long get_number(string n1,long long r){
    long long res=0;
    for(int i=0;i<n1.size();i++){
        if(n1[i]>='a')
            res=res*r+n1[i]-'a'+10;
        else
            res=res*r+n1[i]-'0';
    }
    return res;
}
long long get_low(string str){
    int m=-1;
    for(int i=0;i<str.size();i++){
        if(str[i]>='a')
            m=max(str[i]-'a'+10,m);
        else
            m=max(str[i]-'0',m);
    }
    return (long long)++m;
}

long long find_radix(string n2,long long n){
    long long l=get_low(n2),r=max(n,l);
    while(l<r){
        long long mid=l+r+1>>1;
        long long number=get_number(n2,mid);
        if(number>n||number<0) r=mid-1;
        else l=mid;
    }
    if(get_number(n2,l)!=n) return -1;
    else return l;
}

int main(){
    cin>>n1>>n2>>tag>>radix;
    if(tag==2) swap(n1,n2);
    n=get_number(n1,radix);
    long long res=find_radix(n2,n);
    if(res==-1) printf("Impossible\n");
    else printf("%lld\n",res);
}
1011 World Cup Betting (20分):
#include <iostream>
using namespace std;
float f[3][3];
int n[3];
char c[3]={'W','T','L'};
int main(){
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            scanf("%f",&f[i][j]);
        }
    }
    for(int i=0;i<3;i++){
        float m=-1;
        for(int j=0;j<3;j++){
            if(f[i][j]>m){
                m=f[i][j];
                n[i]=j;
            }
        }
    }
    printf("%c %c %c %.2f",c[n[0]],c[n[1]],c[n[2]],(f[0][n[0]]*f[1][n[1]]*f[2][n[2]]*0.65-1)*2);
}
1012 The Best Rank (25分):

居然一点坑没有,本来怀疑的平均数四舍五入问题,听说都可以。排名的并列问题,我用了如果存在更高的成绩则排名+1,直接过了;

1013 Battle Over Cities (25分):

思路:图的遍历要用深度优先,广度优先会有两个点报错,没想明白;
最后一个测试点几乎就是1000个城市1000000条边,最后都尽量设全局变量,改成邻接矩阵存储才不超时,听说用cin和cout也会超时;

#include <iostream>
#include <cstring>
using namespace std;
int n,m,k,g[1010][1010],st[1010],city;

void dfs(int x){
    st[x]=1;
    for(int i=1;i<=n;i++){
        if(i!=city&&!st[i]&&g[x][i]){
            dfs(i);
        }
    }
}

int main(){
    scanf("%d %d %d",&n,&m,&k);
    while(m--){
        int a,b;
        scanf("%d %d",&a,&b);
        g[a][b]=g[b][a]=1;
    }
    while(k--){
        int res=-1;
        memset(st,0,sizeof st);
        scanf("%d",&city);
        st[city]=1;
        for(int i=1;i<=n;i++){
            if(!st[i]){
                dfs(i);
                res++;
            }
        }
        printf("%d\n",res);
    }
}
1014 Waiting in Line (30分):

思路:队列,我的坑就在于在17:00未完成的会继续服务,我以为题目说17:00银行关门就直接输出17:00了;
因为这个坑不断优化代码,从c语言自己写队列到c++用STL,排队思路也换了两种,时间转化也写了两种orz;
二刷思路:每个窗口模拟一个队列

#include <iostream>
using namespace std;
int n,m,k,q,wait[1010],leave[1010],query[1010],window[25],head[25],tail[25],lines[25][15];
int main(){
    scanf("%d %d %d %d",&n,&m,&k,&q);
    for(int i=0;i<k;i++){
        scanf("%d",&wait[i]);
        if(i<n*m)
            lines[i%n][tail[i%n]++]=i;
    }
    for(int i=n*m;i<k;i++){
        int min=0;
        for(int j=0;j<n;j++){
            if(window[j]+wait[lines[j][head[j]]]<window[min]+wait[lines[min][head[min]]]){
                min=j;
            }
        }
        window[min]+=wait[lines[min][head[min]]];
        leave[lines[min][head[min]]]=window[min];
        head[min]++;
        lines[min][tail[min]++]=i;
    }
    for(int i=0;i<n;i++){
        while(head[i]<tail[i]){
            window[i]+=wait[lines[i][head[i]]];
            leave[lines[i][head[i]++]]=window[i];
        }
    }
    for(int i=0;i<q;i++){
        int temp;
        scanf("%d",&temp);
        if(leave[temp-1]-wait[temp-1]<540)
            printf("%02d:%02d\n",leave[temp-1]/60+8,leave[temp-1]%60);
        else
            printf("Sorry\n");
    }
}
1015 Reversible Primes (20分):

思路:没啥问题,十进制转其他进制再颠倒,再转十进制再判断,注意02是素数,1不是素数(1号测试点考1是不是素数);

#include <iostream>
#include <string>
using namespace std;
int n=0,d,r;

int reverse_prime(int x,int radix){
    string str="";
    while(x){
        str+=x%radix+'0';
        x/=radix;
    }
    int res=0;
    for(int i=0;i<str.size();i++){
        res=res*radix+str[i]-'0';
    }
    return res;
}

bool is_prime(int x){
    if(x<2) return false;
    for(int i=2;i<=x/i;i++)
        if(x%i==0)
            return false;
    return true;
}

int main(){
    while(1){
        scanf("%d %d",&n,&d);
        if(n<0) break;
        r=reverse_prime(n,d);
        if(is_prime(n)&&is_prime(r)) printf("Yes\n");
        else printf("No\n");
    }
}
1016 Phone Bills (25分):

别人测试的坑:测试点0,1:没有消费的用户不能输出
测试点2:on和off日期不在同一天却在同一个小时
测试点3:on和off日期同一天同一个小时
我错了测试点123,异常奇怪。分别用了set和vector存一条条信息,后者要配合sort排序,输出分别用了结构体存一个名字覆盖一次和map,最终发现错在很蠢的地方,以上方法都可以,这题主要锻炼STL的使用。

1017 Queueing at Bank (25分):

有1014做基础没啥问题,时间直接全部转成分钟数或者秒数会比较方便,e.g.08:00:00=28800秒数值做比较

1018 Public Bike Management (30分):

思路:首先用dijkstra找最短路径,如果在发现相同最短路径时直接比较会陷入贪心的问题,测试点7错误,反例:(反例详见:https://blog.csdn.net/weixin_43116322/article/details/103840390)
10 7 7 8
3 2 5 9 9 1 0
0 1 1
0 2 1
1 3 1
2 4 1
3 5 1
4 5 1
5 6 1
6 7 1
解决方法:将dijkstra算法的path数组改为vector< int > path[501],从只记录一个前驱到记录多个,用深度优先算法从目标顶点开始遍历,0点结束并算出一条路上的判断标准值,注意深度优先遍历出来的是倒叙;

1019 General Palindromic Number (20分):

有点1010 Radix的简化版,没啥问题

1020 Tree Traversals (25分):

思路:在后序序列中找根节点,将中序序列划分为两个子序列再找根节点,深度优先的思想;
主要问题在于保存每次找到的根节点,我用了简单的int数组,下标用index记录左右孩子index2+1与index2+2,由于可以有30个节点,最大下标2^32,数组开不了这么大并且循环也会超时,幸好题目最大测试点(最后一个测试点)下标也没超过2000;
其次可以学柳神用map保存,她的代码用了map< int int >,感觉是不是应该map< long long int >才存的下下标;
或者用结构体构造树的节点都可以;

二刷思路:由后序遍历最后一个节点为根节点,在中序遍历中找左右子树,每次将父子关系记录在邻接矩阵中,广度优先搜索遍历邻接矩阵

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int n,post[35],in[35],g[35][35],cnt;

void divide(int lpost,int rpost,int lin,int rin,int root){
    if(lpost>rpost||lin>rin) return ;
    g[root][rpost]=1;
    int t;
    for(int i=lin;i<=rin;i++){
        if(post[rpost]==in[i])
            t=i;
    }
    divide(lpost,lpost+t-lin-1,lin,t-1,rpost);
    divide(lpost+t-lin,rpost-1,t+1,rin,rpost);
}

void bfs(){
    queue<int> q;
    q.push(n-1);
    while(q.size()){
        int t=q.front();
        if(cnt!=n-1) printf("%d ",post[t]);
        else printf("%d\n",post[t]);
        cnt++;
        q.pop();
        for(int i=0;i<n;i++){
            if(g[t][i]){
                q.push(i);
            }
        }
    }
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&post[i]);
    for(int i=0;i<n;i++) scanf("%d",&in[i]);
    divide(0,n-1,0,n-1,34);
    bfs();
}
1021 Deepest Root (25分):

求最大连通图简单,关键在求树的直径,这个方法得记下来!!!!
思路1:求出连通图每一个顶点所对应的最大深度,存入到一个数组中,找最大。这个思路广度深度优先都做了一下测试点3都会超时;
思路2:柳神思路:两次深度优先搜索,先从一个结点dfs后保留最高高度拥有的结点们,然后从这些结点中的其中任意一个开始dfs得到最高高度的结点们,这两个结点集合的并集就是所求;
则么理解呢?就好比捏住一棵树的枝条的顶点,把其他枝条往相反方向捋,从那个方向的最长枝条之一捏住,反方向再捋其他的,甚至可以现实中试一下比如:小时候塑料毽子;

测试点34:第二次只选一个点缕可能遗漏部分点,需要把第一次的所有点加入进来

#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
const int N=100100;
int n,h[N],e[N],ne[N],st[N],idx,cnt,m=-1000;
vector<int> res;
set<int> final_res;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int x,int depth){
    st[x]=1;
    if(depth>m){
        m=depth;
        res.clear();
        res.push_back(x);
    }else if(depth==m){
        res.push_back(x);
    }
    for(int i=h[x];i!=-1;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            dfs(j,depth+1);
        }
    }
}

int main(){
    scanf("%d",&n);
    memset(h,-1,sizeof h);
    if(n==1){
        printf("1");
        return 0;
    }
    for(int i=0;i<n-1;i++){
        int a,b;
        scanf("%d %d",&a,&b);
        add(a,b),add(b,a);
    }
    for(int i=1;i<=n;i++){
        if(!st[i]){
            dfs(i,0);
            cnt++;
        }
    }
    if(cnt!=1)
        printf("Error: %d components\n",cnt);
    else{
        memset(st,0,sizeof st);
        m=-1000;
        for(int i=0;i<res.size();i++){
            final_res.insert(res[i]);
        }
        int x=res[0];
        res.clear();
        dfs(x,0);
        for(int i=0;i<res.size();i++){
            final_res.insert(res[i]);
        }
        for(auto it=final_res.begin();it!=final_res.end();it++){
            printf("%d\n",*it);
        }
    }
}
1022 Digital Library (30分):

思路:简单的话用vector保存,sort自定义排序一下,再查找输出,能做题;柳神用map映射;
问题就在输入函数的运用上,两个坑:

  1. 年份可能不在1000-3000内,用string不用int(测试点2错误);
  2. 真的很难发现!!!!ID可能不是7位,要用printf(“%07d”,ID)补0(测试点3,4错误);
1023 Have Fun with Numbers (20分):

思路:模拟整数乘法;
注意20位数字longlong不够得string存,注意进位就好了;
一刷代码:

#include <iostream>
#include <string.h>
using namespace std;
char number[25],temp[25],double_n[25];
int digit[2][10]={0},n[2];
void calculate(char s[],int b){
    for(int i=0;i<n[b];i++){
        digit[b][s[i]-'0']++;
    }
}
void double_number(){
    int scale=0;
    for(int i=n[0]-1;i>-1;i--){
        int k=(number[i]-'0')*2;
        temp[n[0]-1-i]='0'+k%10+scale;
        scale=k/10;
    }
    if(scale!=0)
        temp[n[0]]='0'+scale;
}
int main(){
    scanf("%s",number);
    n[0]=strlen(number);
    calculate(number,0);
    double_number();
    n[1]=strlen(temp);
    for(int i=n[1]-1;i>-1;i--){
        double_n[n[1]-1-i]=temp[i];
    }
    calculate(double_n,1);
    for(int i=0;i<10;i++){
        if(digit[0][i]!=digit[1][i]){
            printf("No\n");
            printf("%s\n",double_n);
            return 0;
        }
    }
    printf("Yes\n");
    printf("%s\n",double_n);
}
1024 Palindromic Number (25分):

思路:模拟整数加法,string存
没啥大问题,我出现小错误,因为进位上遗漏了原本位上的值9加上进位1产生的进位(测试点568错误,推测应该是很多step的测试点);

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
char N[120];
int n,K;
bool is_pali(){
    char temp[120];
    bool b=1;
    for(int i=0,j=n-1;i<j;i++,j--){
        if(N[i]!=N[j])
            b=0;
    }
    return b;
}
void add(){
    char temp[50];
    int scale=0;
    for(int i=0;i<n;i++){
        temp[i]='0'+(N[i]-'0'+N[n-1-i]-'0'+scale)%10;
        scale=(N[i]-'0'+N[n-1-i]-'0'+scale)/10;
    }
    if(scale!=0){
        temp[n]=scale+'0';
        n++;
    }
    for(int i=0;i<n;i++)
        N[i]=temp[n-1-i];
}
int main(){
    scanf("%s %d",&N,&K);
    n=strlen(N);
    for(int i=0;i<K+1;i++){
        if(is_pali()){
            printf("%s\n%d",N,i);
            return 0;
        }
        else{
            if(i==K){
                printf("%s\n%d",N,i);
                return 0;
            }
            add();
        }
    }
}
1025 PAT Ranking (25分):

排序题,全部整合暴力排序时间复杂度O(n2)会超时;
主要问题在于成绩一样排名一样,我的做法:一个考点暴力求排名,最终排名先排序再扫前后相等的把排名换成一样;其他人是都先求出没有相同排名的两种排名,最后两种排名都替换;
一刷代码:

#include <iostream>
#include <vector>
#include <string.h>
#include <algorithm>
using namespace std;
int N,K;
typedef struct{
    char number[20];
    int score,final_rank,location,local_rank;
}Testee;
vector<Testee> testees;

bool cmp(Testee a,Testee b){
    if(a.score>b.score)
        return 1;
    else if(a.score<b.score)
        return 0;
    else{
        int i=strcmp(a.number,b.number);
        return i<0?1:0;
    }
    
}
int main(){
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        int start=testees.size();
        scanf("%d",&K);
        for(int j=0;j<K;j++){
            Testee temp;
            scanf("%s %d",temp.number,&temp.score);
            temp.location=i+1;
            testees.push_back(temp);
        }
        for(int j=start;j<start+K;j++){
            int l_rank=1;
            for(int k=start;k<start+K;k++)
                if(testees[j].score<testees[k].score)
                    l_rank++;
            testees[j].local_rank=l_rank;
        }
    }
    sort(testees.begin(),testees.end(),cmp);
    for(int i=0;i<testees.size();i++){
        int temp=i+1;
        testees[i].final_rank=temp;
        for(int j=i+1;j<testees.size();j++){
            if(testees[i].score==testees[j].score){
                testees[j].final_rank=temp;
                i++;
            }else
                break;
        }
    }
    printf("%d\n",testees.size());
    for(int i=0;i<testees.size();i++){
        printf("%s %d %d %d\n",testees[i].number,testees[i].final_rank,testees[i].location,testees[i].local_rank);
    }
}
1026 Table Tennis (30分):

逻辑题真的很复杂,不过考试大纲已经不要求这类题目了;

1027 Colors in Mars (20分):

一刷代码:

#include <iostream>
using namespace std;
void radix(int i){
    int high,low;
    high=i/13;
    low=i%13;
    if(high>9&&low<10)
        printf("%c%d",'A'+high-10,low);
    else if(high<10&&low>9)
        printf("%d%c",high,'A'+low-10);
    else if(high>9&&low>9)
        printf("%c%c",'A'+high-10,'A'+low-10);
    else
        printf("%d%d",high,low);
}
int main(){
    int d[3];
    scanf("%d %d %d",&d[0],&d[1],&d[2]);
    printf("#");
    for(int i=0;i<3;i++){
        radix(d[i]);
    }
}
1028 List Sorting (25分)

一刷代码:

#include <iostream>
#include <vector>
#include <string.h>
#include <algorithm>
using namespace std;
typedef struct{
    int ID,grade;
    char name[10];
}Student;
int N,C;
bool cmp1(Student a,Student b){
    return a.ID<b.ID;
}
bool cmp2(Student a,Student b){
    if(strcmp(a.name,b.name)==0)
        return a.ID<b.ID;
    else
        return strcmp(a.name,b.name)<0?1:0;
}
bool cmp3(Student a,Student b){
    if(a.grade==b.grade)
        return a.ID<b.ID;
    else
        return a.grade<b.grade;
}

int main(){
    vector<Student> students;
    scanf("%d %d",&N,&C);
    for(int i=0;i<N;i++){
        Student temp;
        scanf("%d %s %d",&temp.ID,temp.name,&temp.grade);
        students.push_back(temp);
    }
    if(C==1)
        sort(students.begin(),students.end(),cmp1);
    else if(C==2)
        sort(students.begin(),students.end(),cmp2);
    else
        sort(students.begin(),students.end(),cmp3);
    for(int i=0;i<N;i++){
        printf("%06d %s %d\n",students[i].ID,students[i].name,students[i].grade);
    }
}
1029 Median (25分):

好像容易超时,我直接输入到一个vector里,algorithm自带的sort排序求中位数,直接过了;

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<int> sequence;
int main(){
    for(int i=0;i<2;i++){
        scanf("%d",&n);
        for(int j=0;j<n;j++){
            int temp;
            scanf("%d",&temp);
            sequence.push_back(temp);
        }
    }
    sort(sequence.begin(),sequence.end());
    printf("%d",sequence[(int)(sequence.size()-1)/2]);
}
1030 Travel Plan (30分):

经典的dijkstra算法;
这一年有点简单一个多小时都是一遍提交过,可能是前一年太难了;

二刷代码:dijkstra+dfs输出,如果存有向图则12两测试点会报错。

#include <iostream>
#include <cstring>
using namespace std;
const int N=505;
int n,m,s,d,g[N][N][2],dist[N],st[N],path[N],cost[N];

void dijkstra(){
    dist[s]=0;
    cost[s]=0;
    for(int i=0;i<n;i++){
        int t=-1;
        for(int j=0;j<n;j++){
            if(!st[j]&&(t==-1||dist[t]>dist[j])){
                t=j;
            }
        }
        st[t]=1;
        for(int j=0;j<n;j++){
            if(dist[j]>dist[t]+g[t][j][0]){
                dist[j]=dist[t]+g[t][j][0];
                cost[j]=cost[t]+g[t][j][1];
                path[j]=t;
            }else if(dist[j]==dist[t]+g[t][j][0]&&cost[j]>cost[t]+g[t][j][1]){
                cost[j]=cost[t]+g[t][j][1];
                path[j]=t;
            }
        }
    }
}

void dfs(int x){
    if(x==s){
        printf("%d ",x);
        return ;
    }
    dfs(path[x]);
    printf("%d ",x);
}

int main(){
    scanf("%d %d %d %d",&n,&m,&s,&d);
    memset(g,0x3f,sizeof g);
    memset(dist,0x3f,sizeof dist);
    memset(cost,0x3f,sizeof cost);
    while(m--){
        int a,b,c,e;
        scanf("%d %d %d %d",&a,&b,&c,&e);
        g[a][b][0]=g[b][a][0]=c,g[a][b][1]=g[b][a][1]=e;
    }
    dijkstra();
    dfs(d);
    printf("%d %d\n",dist[d],cost[d]);
}
1031 Hello World for U (20分):

主要问题在于理解题目意思,总结为n1,n2,n3尽可能相等,且n2必须大于等于n1,n3;

#include <iostream>
#include <string>
using namespace std;
int main(){
    string str;
    cin>>str;
    int size=str.size(),n1,n2;
    n1=(size+2)/3-1;
    n2=size-2*n1;
    for(int i=0;i<n1;i++){
        printf("%c",str[i]);
        for(int j=0;j<n2-2;j++)
            printf(" ");
        printf("%c\n",str[size-i-1]);
    }
    for(int i=n1;i<n2+n1;i++)
        printf("%c",str[i]);
}
1032 Sharing (25分):

思路:计算两个字符串长度,由于最后要共享,即后一半node相同,故先让字符串长的遍历两者之差。得到长度相等的两个字符串,同时后移,如果两者next相等就直接输出;
测试点5如果单纯用数组记录,每次遍历O(N)会超时,用空间换时间,hash标记数组nodes[1000000],地址为下标每次时间复杂度O(1)。
测试点1,3答案是-1;
测试点4错误,记得printf格式05d;

二刷思路:用一个一维数组记录链表,一个标记数组记录即可,注意输出格式!

#include <iostream>
using namespace std;
const int N=100010;
int n1,n2,m,g[N],st[N];
char t;
int main(){
    scanf("%d %d %d",&n1,&n2,&m);
    while(m--){
        int a,b;
        scanf("%d %c %d",&a,&t,&b);
        g[a]=b;
    }
    while(n1!=-1){
        st[n1]=1;
        n1=g[n1];
    }
    while(n2!=-1){
        if(st[n2]==1){
            printf("%05d\n",n2);
            return 0;
        }
        n2=g[n2];
    }
    printf("-1\n");
}
1033 To Fill or Not to Fill (25分)

思路:先对车站按距离排序,从0号车站开始,如果满油能到达的范围内,能找到比出发点便宜的最近的站点,买刚好的油,到点油量为0;反之油加满到最远的站点;其中增加到不了下一个站点或到达终点的判断;
死在测试点2,如果思路没考虑到这个点,真的很难发现,参考别人的错误:
第1个测试点包含了多个加油站坐标相同的数据。
第2个测试点包含了起点没有加油站的数据。
第4个测试点包含了有多个加油站距离目标城市的距离小于等于油箱最大容积的行驶距离且距离目标城市越近的加油站油越贵。
第0,6个测试点包含了有多个加油站距离目标城市的距离小于等于油箱最大容积的行驶距离且距离目标城市越近的加油站油越便宜。
附上测试过程数据:

1034 Head of a Gang (30分)

思想:用了并查集的方法,也可以当图来遍历dfs求连通分量。遍历数据时,分三种情况,一个在map中,都在map中,都不在,处理father是谁问题。最后遍历map统计团伙信息,存入vector中。
测试点2,5:最终答案未排序;
测试点4:应该只有用并查集才会出错,加入map时,若两者属于两个不同团伙,则需将两个团伙合并,即更新另一个团伙所有成员的father值。

一刷用dfs求连通分量会比并查集代码短一些;
二刷并查集方法的代码:

#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <vector>
using namespace std;
typedef struct{
    string head;
    int weight=0,number=0;
}Gang;
int n,k;
unordered_map<string,pair<int,int>> gangs;
unordered_map<string,pair<string,int>> persons;
vector<pair<string,int>> res;
string find_f(string str){
    if(persons[str].first!=str) persons[str].first=find_f(persons[str].first);
    return persons[str].first;
}
int main(){
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++){
        string a,b;
        int w;
        cin>>a>>b>>w;
        if(persons.count(a)&&persons.count(b)){
            persons[a].second+=w;
            persons[b].second+=w;
            string fa=find_f(a),fb=find_f(b);
            if(fa!=fb){
                persons[fb].first=fa;
            }
        }
        else if(!persons.count(a)&&persons.count(b)){
            persons[a].second=w;
            persons[a].first=find_f(b);
            persons[b].second+=w;
        }else if(persons.count(a)&&!persons.count(b)){
            persons[b].second=w;
            persons[b].first=find_f(a);
            persons[a].second+=w;
        }else{
            persons[a].second=w;
            persons[a].first=a;
            persons[b].second=w;
            persons[b].first=a;
        }
    }
    for(auto it=persons.begin();it!=persons.end();it++){
        //cout<<it->first<<" "<<it->second.first<<" "<<it->second.second<<endl;
        string father=find_f(it->second.first);
        if(!gangs.count(father)){
            int p=1;
            if(it->first!=father)
                p++;
            gangs[father]={it->second.second,p};
        }else{
            gangs[father].first+=it->second.second;
            if(it->first!=father)
                gangs[father].second++;
        }
    }
    for(auto it=gangs.begin();it!=gangs.end();it++){
        if(it->second.first/2>k&&it->second.second>=3){
            res.push_back({it->first,it->second.second});
        }
    }
    cout<<res.size()<<endl;
    for(int i=0;i<res.size();i++){
        int weight=-1;string head;
        for(auto it=persons.begin();it!=persons.end();it++){
            if(res[i].first==it->second.first&&it->second.second>weight){
                weight=it->second.second;
                head=it->first;
            }
        }
        res[i].first=head;
    }
    sort(res.begin(),res.end());
    for(int i=0;i<res.size();i++){
        cout<<res[i].first<<" "<<res[i].second<<endl;
    }
}
1035 Password (20分):

注意输出格式,N=1时单数,N>1时负数形式;

1036 Boys vs Girls (25分):
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int,string>> males;
vector<pair<int,string>> females;
int n;
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        int grade;char gender;string name,ID;
        cin>>name>>gender>>ID>>grade;
        if(gender=='M') males.push_back({grade,name+" "+ID});
        else females.push_back({grade,name+" "+ID});
    }
    if(!females.size()) printf("Absent\n");
    else{
        sort(females.begin(),females.end());
        cout<<females[females.size()-1].second<<endl;
    }
    if(!males.size()) printf("Absent\n");
    else{
        sort(males.begin(),males.end());
        cout<<males[0].second<<endl;
    }
    if(males.size()==0||females.size()==0) printf("NA\n");
    else printf("%d\n",females[females.size()-1].first-males[0].first);
}
1037 Magic Coupon (25分):

奖券和商品分正负排序,因为可以不用完,故正正负负相乘即可

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int C,P,sum;
vector<int> c_p,c_n,p_p,p_n;
int main(){
    scanf("%d",&C);
    for(int i=0;i<C;i++){
        int temp;
        scanf("%d",&temp);
        if(temp>0)
            c_p.push_back(temp);
        else
            c_n.push_back(-temp);
    }
    scanf("%d",&P);
    for(int i=0;i<P;i++){
        int temp;
        scanf("%d",&temp);
        if(temp>0)
            p_p.push_back(temp);
        else
            p_n.push_back(-temp);
    }
    sort(c_p.begin(),c_p.end(),greater<int>());
    sort(c_n.begin(),c_n.end(),greater<int>());
    sort(p_p.begin(),p_p.end(),greater<int>());
    sort(p_n.begin(),p_n.end(),greater<int>());
    for(int i=0;i<c_p.size()&&i<p_p.size();i++){
        sum+=c_p[i]*p_p[i];
    }
    for(int i=0;i<c_n.size()&&i<p_n.size();i++){
        sum+=c_n[i]*p_n[i];
    }
    printf("%d\n",sum);
}
1038 Recover the Smallest Number (30分):

代码简洁来说的思路是cmp排序的函数return (a+b)<(b+a),即判断两个string谁在前会更小;
我本来的思路是两个string3214和32,长string的第一位3加到短string进行比较,即3214与323比较,但是如果加完仍相同需要一直比较(百度也有人这个思路认为只要比较3位),有反例例如32321和32,就很麻烦;
测试点2:小坑可能类似于测试数据:3 000 0 00,结果应该是0;

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
int N;
vector<string> numbers;
bool cmp(string a,string b){
    return (a+b)<(b+a);
}
int main(){
    scanf("%d",&N);
    string temp;
    for(int i=0;i<N;i++){
        cin>>temp;
        numbers.push_back(temp);
    }
    sort(numbers.begin(),numbers.end(),cmp);
    int first=0;
    string result="";
    for(int i=0;i<N;i++){
        result+=numbers[i];
    }
    for(int i=0;i<result.size();i++){
        if(result[i]!='0'){
            first=1;
        }
        if(first)
            printf("%c",result[i]);
    }
    if(!first)
        printf("0");
}
1039 Course List for Student (25分):

思想:用unordered_map<string,vector>存即可

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
unordered_map<string,vector<int>> students;
int N,K,c,C;
int main(){
    scanf("%d %d",&N,&K);
    for(int i=0;i<K;i++){
        scanf("%d %d",&c,&C);
        for(int j=0;j<C;j++){
            string name;
            cin>>name;
            students[name].push_back(c);
        }
    }
    for(int i=0;i<N;i++){
        string name;
        cin>>name;
        sort(students[name].begin(),students[name].end());
        printf("%s %d",name.c_str(),students[name].size());
        for(int j=0;j<students[name].size();j++)
            printf(" %d",students[name][j]);
        printf("\n");
    }
}
1040 Longest Symmetric String (25分):

思想:暴力法或者动态规划,动态规划要设二维数组s[i][j],即下标i - j间的字符串为对称,初始条件s[i][i]=1,s[i][i+1]单个元素和相邻相同字符串必然对称,注意之后判断的外层循环要用字符串长度,判断条件为s[i+1][i+length-1] == 1 && str[i] == str[i+length],注意一下循环边界就好了;
二刷代码(动归):

#include <iostream>
using namespace std;
bool s[1005][1005];
string str;
int len;
int res=1;
int main(){
    getline(cin,str);
    len=str.size();
    if(len==0){
        printf("0\n");
        return 0;
    }
    for(int i=0;i<len;i++) s[i][1]=1;
    for(int i=0;i<len-1;i++){
        if(str[i]==str[i+1]){
            s[i][2]=1;
            res=2;
        }
    }
    for(int k=3;k<=len;k++){
        for(int i=0;i<=len-k;i++){
            if(str[i]==str[i+k-1]&&s[i+1][k-2]){
                s[i][k]=1;
                if(k>res)
                    res=k;
            }
        }
    }
    printf("%d\n",res);
}
1041 Be Unique (20分):

思路:用两个数组,一个记录次序的普通数组,一个记录次数的hash数组;

#include <iostream>
#include <vector>
using namespace std;
int n,h[10010];
vector<int> v;
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        v.push_back(temp);
        h[temp]++;
    }
    for(int i=0;i<v.size();i++){
        if(h[v[i]]==1){
            printf("%d\n",v[i]);
            return 0;
        }
    }
    printf("None\n");
}
1042 Shuffling Machine (20分):

思路:题意说每次将i位置的牌插到j位置,看似每次要移动很多牌,但因为每个位置只出现一次,移到的j位置就是最终位置,可能只有我觉得有个小弯要绕一下;
一刷代码:

#include <iostream>
#include <vector>
#include <string>
using namespace std;
string cards[21][54];
int K;
int order[54];
int main(){
    string type[4]={"S","H","C","D"};
    for(int i=0;i<4;i++){
        for(int j=0;j<13;j++)
            cards[0][i*13+j]=type[i]+to_string(j+1);
    }
    cards[0][52]="J1";
    cards[0][53]="J2";
    scanf("%d",&K);
    for(int i=0;i<54;i++){
        scanf("%d ",&order[i]);
    }
    for(int i=0;i<K;i++){
        for(int j=0;j<54;j++){
            cards[i+1][order[j]-1]=cards[i][j];
        }
    }
    for(int i=0;i<54;i++){
        printf("%s",cards[K][i].c_str());
        if(i!=53)
            printf(" ");
    }
}
1043 Is It a Binary Search Tree (25分):

思路:前序转后序,深度优先遍历,关于镜像等等问题都用逻辑判断一口气解决的,有点复杂,注意边界条件等等,不过没有坑;
深度优先遍历找后序,每棵子树从根节点出发,分为小于根节点部分与大于根节点部分,若大小转折超过两次或大小顺序不一致则错误;

1044 Shopping in Mars (25分):

思路:暴力法两个点超时,柳神用了二分,事实上这好像是一道经典的尺取法(双指针)问题,附尺取法讲解,刚好他的例题和这道题几乎一样https://www.jianshu.com/p/252b8c20f91c;
测试点2:巨坑,气的我,我设了一个int常数10000000来找最小的和,常数改为0x7fffffff就正确了;
测试点3:听说数组太小过不了;
二刷代码,双指针模版题:

#include <iostream>
#include <vector>
using namespace std;
int n,m,sum,res_sum=100000010;
vector<int> d;
vector<pair<int,int>> res;
int main(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++){
        int temp;
        scanf("%d",&temp);
        d.push_back(temp);
    }
    for(int i=0,j=0;i<n;i++){
        sum+=d[i];
        while(sum-d[j]>=m){
            sum-=d[j];
            j++;
        }
        if(sum>=m&&sum<res_sum){
            res_sum=sum;
            res.clear();
            res.push_back({j+1,i+1});
        }else if(sum>=m&&sum==res_sum)
            res.push_back({j+1,i+1});
    }
    for(int i=0;i<res.size();i++){
        printf("%d-%d\n",res[i].first,res[i].second);
    }
}
1045 Favorite Color Stripe (30分):

思路:经典的动态规划题目,一个数组保存数组的顺序优先级,位置i的dp[i]为遍历0 - (i-1)所有颜色,若颜色优先级低于i的颜色且dp[j]最大,dp[i]=dp[j]+1,反之为0,注意剔除不是喜爱颜色的值;

#include <iostream>
using namespace std;
int N,M,L,favor_order[203],len[10010],dp[10010]={0};
int main(){
    scanf("%d %d",&N,&M);
    fill(favor_order,favor_order+203,300);
    for(int i=0;i<M;i++){
        int temp;
        scanf("%d",&temp);
        favor_order[temp]=i;
    }
    scanf("%d",&L);
    for(int i=0;i<L;i++){
        scanf("%d",&len[i]);
    }
    dp[0]=1;
    for(int i=0;i<L;i++){
        for(int j=i-1;j>-1&&favor_order[len[i]]!=300;j--){
            if(favor_order[len[j]]<=favor_order[len[i]]){
                dp[i]=dp[j]+1;
                break;
            }
        }
        if(dp[i]==0&&favor_order[len[i]]!=300){
            dp[i]=1;
        }
    }
    int max=0;
    for(int i=0;i<L;i++){
        if(dp[i]>max){
            max=dp[i];
        }
    }
    printf("%d",max);
}
1046 Shortest Distance (20分):

思路:由于最后一个测试点会超时,所以不能来一组数据算一组数据;提前用数组保存由1这个点出发到各点距离,之后具体加减运算即可;
二刷思路:前缀和

#include <iostream>
#include <cmath>
using namespace std;
int n,m,pre[100010],a,b;
int main(){
    scanf("%d",&n);
    for(int i=1;i<n+1;i++){
        int temp;
        scanf("%d",&temp);
        if(i!=n) pre[i]=pre[i-1]+temp;
        else pre[0]=pre[n-1]+temp;
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++){
        scanf("%d %d",&a,&b);
        int sum=(pre[b-1]-pre[a-1]+pre[0])%pre[0];
        printf("%d\n",min(sum,pre[0]-sum));
    }
}
1047 Student List for Course (25分):

简单的vector+sort;
一刷代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int N,K;
vector<string> courses[2501];
int main(){
    scanf("%d %d",&N,&K);
    for(int i=0;i<N;i++){
        string name;
        int C;
        cin>>name;
        scanf("%d",&C);
        for(int j=0;j<C;j++){
            int c;
            scanf("%d",&c);
            courses[c].push_back(name);
        }
    }
    for(int i=1;i<K+1;i++){
        sort(courses[i].begin(),courses[i].end());
    }
    for(int i=1;i<K+1;i++){
        printf("%d %d\n",i,courses[i].size());
        for(int j=0;j<courses[i].size();j++){
            printf("%s\n",courses[i][j].c_str());
        }
    }
}
1048 Find Coins (25分):

思路:利用vector,sort函数,find函数,本以为可以超方便的用自带函数二分实现不超时,结果还是两个测试点超时了;思路还是尺取法(双指针)和1044题类似;
测试点五:数据应该是只给一个coin,这个coin的值=M;即:
1 15
15

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N,M,l=100010,r=100010;
vector<int> coins;
int main(){
    scanf("%d %d",&N,&M);
    if(N<=1){
        printf("No Solution");
        return 0;
    }
    for(int i=0;i<N;i++){
        int temp;
        scanf("%d",&temp);
        coins.push_back(temp);
    }
    sort(coins.begin(),coins.end());
    for(int i=0,j=0;i<N;i++){
        while(j<i-1&&coins[i]+coins[j]<M) j++; //注意j<i-1,即j!=i
        while(j>0&&coins[i]+coins[j]>M) j--;
        if(coins[i]+coins[j]==M){
            if(coins[j]<l){
                l=coins[j];
                r=coins[i];
            }
        }
    }
    if(l!=100010) printf("%d %d\n",l,r);
    else printf("No Solution\n");
}
1049 Counting Ones (30分):简单数学

思路:输入的数分别存int和string,取string数组从高位到低位,按每位出现的1累加:
若位数k=0跳过;
若k=1,举例:若取到123的1,结果result+=0-99出现的所有1 + 24个百位的1;
若k>1,举例:若取321的3,结果result+=3次0-99出现的1 + 100-199百位100个1;
代码很短,附一下:

#include <iostream>	#include <cmath>	#include <string> using namespace std;
int main(){
    int N,result=0;
    scanf("%d",&N);
    string str=to_string(N);
    for(int i=str.size()-1;i>-1;i--){
        int temp=str[str.size()-i-1]-'0';
        if(temp==1)
            result+=i*pow(10,i-1)+N%(int)pow(10,i)+1;
        else if(temp!=0)
            result+=temp*i*pow(10,i-1)+pow(10,i);
    }cout<<result<<endl;
}
1050 String Subtraction (20分):

简单的hash;

#include <iostream>
#include <string>
using namespace std;
int h[129]={0};
string str1,str2;
int main(){
    getline(cin,str1);
    getline(cin,str2);
    for(int i=0;i<str2.size();i++){
        h[(int)str2[i]]=1;
    }
    for(int i=0;i<str1.size();i++){
        if(!h[(int)str1[i]])
            printf("%c",str1[i]);
    }
}
1051 Pop Sequence (25分):

思路:一开始直接从结果入手,从pop输出数组中前后关系判断YES/NO,发现第二个测试点错误,很奇怪(如果有人和我一样并找到了问题,请务必评论告知orz);
看了柳神,简单模拟,不断向栈推入元素,若栈顶元素与题目pop数组相同则pop掉栈顶元素并数组位置后移,最终判断YES/NO;
一刷模拟代码:

#include <iostream>
#include <stack>
using namespace std;
int M,N,K;
stack<int> stacks;
int main(){
    scanf("%d %d %d",&M,&N,&K);
    for(int i=0;i<K;i++){
        int k=1;
        while(!stacks.empty())
            stacks.pop();
        for(int j=0;j<N;j++){
            int pop;
            scanf("%d",&pop);
            if(stacks.size()!=0&&stacks.top()==pop){
                stacks.pop();
                if(j==N-1)
                    printf("YES\n");
                continue;
            }
            while(stacks.size()<M){
                stacks.push(k);
                k++;
                if(stacks.top()==pop){
                    stacks.pop();
                    if(j==N-1)
                        printf("YES\n");
                    break;
                }
            }
            if(j==N-1&&stacks.size()>=M){
                printf("NO\n");
                break;
            }
        }
    }
}
1052 Linked List Sorting (25分):

思路:hash。开100000大小类型为自定义结构体的hash数组,如果再用vector来记录访问的节点,最后一个测试点会内存不够;可以在结构体中加bool字符标记是否被访问,之后直接排序,数组最前面的就是访问节点;
测试点4:不仅仅会内存不够,还需要特判如果N0||head node address-1,直接输出“0 -1”;
一刷代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef struct{
    int address,key,next;
    bool is_in=0;
}Node;
Node h[100010];
bool cmp(Node &a,Node &b){
    if(a.is_in&&!b.is_in)
        return 1;
    else if(!a.is_in&&b.is_in)
        return 0;
    else
        return a.key<b.key;
}
int main(){
    int N,start;
    scanf("%d %d",&N,&start);
    for(int i=0;i<N;i++){
        Node temp;
        scanf("%d %d %d",&temp.address,&temp.key,&temp.next);
        h[temp.address]=temp;
    }
    if(start==-1){
        printf("0 -1");
        return 0;
    }
    while(start!=-1){
        h[start].is_in=1;
        start=h[start].next;
    }
    sort(h,h+100010,cmp);
    int size=N;
    for(int i=0;i<N;i++){
        if(!h[i].is_in){
            size=i;
            break;
        }
        h[i].next=h[i+1].address;
    }
    if(size==0){
        printf("0 -1");
        return 0;
    }
    printf("%d %05d\n",size,h[0].address);
    h[size-1].next=-1;
    for(int i=0;i<size-1;i++){
        printf("%05d %d %05d\n",h[i].address,h[i].key,h[i].next);
    }
    printf("%05d %d %d\n",h[size-1].address,h[size-1].key,h[size-1].next);
}
1053 Path of Equal Weight (30分):

思路:优先根据weight值对每个节点的孩子进行排序,之后用深度优先遍历,若路径上的weight和符合要求且该节点无孩子,直接输出整条路径(用vector类型的path记录);
两个核心点:
在dfs前对邻接矩阵的同一个根节点的孩子排序,使dfs出来的结果直接有序,若对结果排序会很复杂;
dfs过程中维护一个path路径,若遍历到根节点且weight满足则打印path路径。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N,M,S,weight[100];
vector<int> non_leaf[100];
bool cmp(int a,int b){
    return weight[a]>weight[b];
}
vector<int> path;
void dfs(int root,int sum){
    path.push_back(root);
    sum+=weight[root];
    if(sum>S){
        return ;
    }else if(sum==S&&non_leaf[root].size()==0){
        for(int i=0;i<path.size();i++){
            printf("%d",weight[path[i]]);
            if(i!=path.size()-1)
                printf(" ");
        }
        printf("\n");
    }else{
        for(int i=0;i<non_leaf[root].size();i++){
            dfs(non_leaf[root][i],sum);
            path.pop_back();
        }
    }
}

int main(){
    scanf("%d %d %d",&N,&M,&S);
    for(int i=0;i<N;i++){
        scanf("%d",&weight[i]);
    }
    for(int i=0;i<M;i++){
        int id,n;
        scanf("%d %d",&id,&n);
        for(int j=0;j<n;j++){
            int temp;
            scanf("%d",&temp);
            non_leaf[id].push_back(temp);
        }
    }
    for(int i=0;i<99;i++){
        if(non_leaf[i].size()!=0){
            sort(non_leaf[i].begin(),non_leaf[i].end(),cmp);
        }
    }
    dfs(0,0);
}
1054 The Dominant Color (20分):

思路:简单的hash;

1055 The World’s Richest (25分):

熟练运用结构体+algorithm中的sort函数即可;
一刷代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int N,K,M,Amin,Amax;
typedef struct{
    string name;
    int age,worth;
}Person;
vector<Person> persons;
bool cmp(Person a,Person b){
    return a.worth!=b.worth?a.worth>b.worth:a.age!=b.age?a.age<b.age:a.name<b.name;
}
int main(){
    scanf("%d %d",&N,&K);
    for(int i=0;i<N;i++){
        Person temp;
        cin>>temp.name;
        scanf("%d %d",&temp.age,&temp.worth);
        persons.push_back(temp);
    }
    sort(persons.begin(),persons.end(),cmp);
    for(int i=0;i<K;i++){
        scanf("%d %d %d",&M,&Amin,&Amax);
        int count=0;
        printf("Case #%d:\n",i+1);
        for(int i=0;i<N;i++){
            if(count>=M)
                break;
            if(persons[i].age<=Amax&&persons[i].age>=Amin){
                printf("%s %d %d\n",persons[i].name.c_str(),persons[i].age,persons[i].worth);
                count++;
            }
        }
        if(count==0)
            printf("None\n");
    }
}
1056 Mice and Rice (25分)

思路:分组找最大值,将总的vector分组,用一个vector数组存贮每组最大值然后再合并为总的,用递归。注意排名问题,简单的方法是新产生的vector的size+1就是被淘汰的排名,即假设5个人晋级则其余人排名为5+1;
坑:题目很难读懂,特别是第一段Mice and Rice部分的长篇大论和题目没啥关系,其次If there are less than N​G mice at the end of the player’s list, then all the mice left will be put into the last group.这句话让我以为多出来的合并orz;
测试点无坑;
一刷代码:

#include <iostream>
#include <vector>
using namespace std;
int P,G;
int weight[1000],point[1000]={0};
vector<int> pro;
int first;
void win(int length){
    vector<int> groups[length/G+1];
    int max[length/G+1];
    fill(max,max+length/G+1,-1);
    for(int i=0;i<length;i++){
        if(weight[pro[i]]>max[i/G]){
            groups[i/G].clear();
            max[i/G]=weight[pro[i]];
            groups[i/G].push_back(pro[i]);
        }else if(weight[pro[i]]==max[i/G]){
            groups[i/G].push_back(pro[i]);
        }
    }
    int size=0;
    for(int i=0;i<length/G+1;i++){
        size+=groups[i].size();
    }
    for(int i=0;i<length;i++){
        point[pro[i]]=size+1;
    }
    pro.clear();
    for(int i=0;i<length/G+1;i++){
        for(int j=0;j<groups[i].size();j++){
            pro.push_back(groups[i][j]);
        }
    }
    if(pro.size()==1)
        first=pro[0];
    if(pro.size()>1)
        win(pro.size());
}
int main(){
    scanf("%d %d",&P,&G);
    for(int i=0;i<P;i++){
        scanf("%d",&weight[i]);
    }
    for(int i=0;i<P;i++){
        int temp;
        scanf("%d",&temp);
        pro.push_back(temp);
    }
    win(P);
    point[first]=1;
    for(int i=0;i<P;i++){
        printf("%d",point[i]);
        if(i!=P-1)
            printf(" ");
    }
}
1057 Stack (30分):

思路:树状数组,最后再看吧

1058 A+B in Hogwarts (20分):

思路:简单的进制转化;

#include <iostream>
using namespace std;
int g1,s1,k1,g2,s2,k2,g3,s3,k3;
int main(){
    scanf("%d.%d.%d %d.%d.%d",&g1,&s1,&k1,&g2,&s2,&k2);
    k3=(k1+k2)%29;
    s3=(s1+s2+(k1+k2)/29)%17;
    g3=g1+g2+(s1+s2+(k1+k2)/29)/17;
    printf("%d.%d.%d",g3,s3,k3);
}
1059 Prime Factors (25分):

二刷思路:求约数模版题

#include <iostream>
#include <map>
using namespace std;
int n;
map<int,int> m;
void get_prime(int x){
    for(int i=2;i<=x/i;i++){
        while(x%i==0){
            x/=i;
            m[i]++;
        }
    }
    if(x!=1) m[x]++;
}
int main(){
    scanf("%d",&n);
    if(n==1){ printf("1=1\n");return 0;}
    get_prime(n);
    printf("%d=",n);
    for(auto it=m.begin();it!=m.end();it++){
        if(it!=m.begin())
            printf("*");
        if(it->second!=1)
            printf("%d^%d",it->first,it->second);
        else
            printf("%d",it->first);
    } printf("\n");
}
1060 Are They Equal (25分):

思路:字符串处理,结果为科学计数法,题目不能但测试点很坑;
注意:10的0次方和1次方都要写
测试点6:关于全0的问题,e.g. 1 0.1 0 1 0.0 0.1等等
其他测试点,下面这篇文章给出了16个测试案例,可以一个个查找自己的错误:
https://blog.csdn.net/lannister_awalys_pay/article/details/90451536

1061 Dating (20分):

这题的主要问题在于读懂题目;
题目,三个字符条件分别为:

  1. 第一个字符串和第二个字符串相同位置上,且字符相同,且字符在A - G之间;
  2. 第一个字符串和第二个字符串相同位置上且字符相同,在上一个字符查找之后, 在0 - 9或A - N之间;
  3. 第三个字符串和第四个字符串相同位置上,且位置相同输出位置i在a-z与A-Z之间;
    一刷代码:
#include <iostream>
#include <string.h>
using namespace std;
string str[4];
string week[7]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
int main(){
    for(int i=0;i<4;i++){
        getline(cin,str[i]);
    }
    int n=0;
    for(int i=0;i<str[0].size()&&i<str[1].size();i++){
        if(n==0&&str[0][i]==str[1][i]&&str[0][i]<'H'&&str[0][i]>='A'){
            n=1;
            printf("%s ",week[str[0][i]-'A'].c_str());
        }
        else if(n==1&&str[0][i]==str[1][i]){
            if(str[0][i]<='N'&&str[0][i]>='A'){
                printf("%02d:",str[0][i]-'A'+10);
                break;
            }else if(str[0][i]<='9'&&str[0][i]>='0'){
                printf("%02d:",str[0][i]-'0');
                break;
            }
        }
    }
    for(int i=0;i<str[2].size()&&i<str[3].size();i++){
        if(str[2][i]==str[3][i]&&((str[2][i]<='Z'&&str[2][i]>='A')||(str[2][i]<='z'&&str[2][i]>='a'))){
            printf("%02d",i);
            break;
        }
    }
}
1062 Talent and Virtue (25分):

思路:vector+自定义cmp的sort排序;
还是注意读题,小人与愚人的条件;
一刷代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N,L,H;
typedef struct{
    int ID,talent,virtue,level;
}Person;
vector<Person> persons;
bool cmp(Person a,Person b){
    return a.level!=b.level?a.level<b.level:a.talent+a.virtue!=b.talent+b.virtue?a.talent+a.virtue>b.talent+b.virtue:a.virtue!=b.virtue?a.virtue>b.virtue:a.ID<b.ID;
}
int main(){
    scanf("%d %d %d",&N,&L,&H);
    for(int i=0;i<N;i++){
        Person temp;
        scanf("%d %d %d",&temp.ID,&temp.virtue,&temp.talent);
        if(temp.talent>=H&&temp.virtue>=H)
            temp.level=0;
        else if(temp.virtue>=H&&temp.talent>=L)
            temp.level=1;
        else if(temp.talent<=temp.virtue)
            temp.level=2;
        else if(temp.talent>temp.virtue)
            temp.level=3;
        if(temp.talent>=L&&temp.virtue>=L)
            persons.push_back(temp);
    }
    sort(persons.begin(),persons.end(),cmp);
    printf("%d\n",persons.size());
    for(int i=0;i<persons.size();i++){
        printf("%d %d %d\n",persons[i].ID,persons[i].virtue,persons[i].talent);
    }
}
1063 Set Similarity (25分):

思路:首先用STL中set容器保存每一行set数据,剔除数据相同;
比较两个set,分别用了:

  1. hash数组查找,后三个测试点错误;
  2. set自带find()函数通过;
  3. 将查找的两个set合并为一个set,结果直接输出(set1.size+set2.size-总set.size)/总set.size*100%,最后一个测试点超时;

hash的错误暂时不管,思考了一下后两种方法:set容器由红黑树实现的各种操作插入、查看、删除时间复杂度都为: O(logN),假设两个set容量都为N,则方法2复杂度为O(NlogN),而后者时间复杂度至少为O(2NlogN);
一刷代码:

#include <iostream>
#include <set>
using namespace std;
int N,M,K,s1,s2;
int main(){
    scanf("%d",&N);
    set<int> s[N];
    for(int i=0;i<N;i++){
        scanf("%d",&M);
        for(int j=0;j<M;j++){
            int temp;
            scanf("%d",&temp);
            s[i].insert(temp);
        }
    }
    scanf("%d",&K);
    for(int i=0;i<K;i++){
        scanf("%d %d",&s1,&s2);
        int count=0;
        set<int> temp;
        for(auto it=s[s2-1].begin();it!=s[s2-1].end();it++){
            if(s[s1-1].find(*it)!=s[s1-1].end()){
                count++;
            }
        }
        printf("%.1f",(float)count/(s[s1-1].size()+s[s2-1].size()-count)*100);
        printf("%\n");
    }
}
1064 Complete Binary Search Tree (30分):

思路:自己想了好久,最终看了柳神的,由于完全二叉搜索树的中序遍历为从小到大,所以在对数组排序后,有序数组就是一个中序遍历队列,题目转换为中序遍历转层序遍历;

#include <iostream>
#include <algorithm>
using namespace std;
int in[1010], level[1010], n, t = 0;
void inOrder(int root) {
    if (root >= n) return ;
    inOrder(root * 2 + 1);
    level[root] = in[t++];
    inOrder(root * 2 + 2);
}
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &in[i]);
    sort(in, in + n);
    inOrder(0);
    printf("%d", level[0]);
    for (int i = 1; i < n; i++)
        printf(" %d", level[i]);
    return 0;
}
1065 A+B and C (64bit) (20分):

思路:

  1. 用longlong计算,特判两种溢出情况,正溢出必为true,负溢出必为false;
  2. 用long double存,直接a+b>c就好了,这里注意几种输入输出:
    float类型:%f;
    double类型:%lf;
    long double类型:%Lf;
#include <iostream>
using namespace std;
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        long double a, b, c;
        scanf("%Lf %Lf %Lf", &a, &b, &c);
        if(a + b > c) {
            printf("Case #%d: true\n", i + 1);
        } else {
            printf("Case #%d: false\n", i + 1);
        }
    }
    return 0;
}
1066 Root of AVL Tree (25分):

思路:标准的AVL树题目,涉及AVL树的节点创建,插入等等操作(考前联系);
提供一种投机取巧的方法试探法,限于考试时间不够时使用。由于题目仅求根节点,而其位置总会在有序数组的中间,由于结果情况较少故能一种种试探得分,直接输出下标N/2能得17分;特判偶数时下标N/2+1,又能4分;N=11时下标为4,满分(最后一种可能难以试探,但考试时间不够得21分不失为一种投机取巧得好方法);

1067 Sort with Swap(0, i) (25分):

思路:

  1. 模拟swap操作,若0不在下标为0的位置则不断swap,直到0回到0位置,这里为了swap操作方便可以用类似hash数组的方式记录每个值的下标位置;
  2. 标记数组标记仍有问题的位置,循环遍历,若有问题,将该值与0交换,执行步骤1,直到标记数组所有位置都ok;
1068 Find More Coins (30分):

思路:比标准的01背包问题,多了一个二维数组记录每个总花费用的硬币,先对硬币从大到小排序就可以优先获得面值小的硬币,dp数组的空间复杂度可以优化到一位数组,算法笔记讲的很清楚;

1069 The Black Hole of Numbers (20分):

思路:善于利用已有库函数:

  1. string类型转int类型:int num = atoi(N.c_str());
  2. int类型转string类型:to_string();
  3. string类型直接排序sort(),反转reverse();

注意:数字可能不是四位数,转成字符要前面添0,这个步骤只能手动了,这个问题没有考虑到的话好像中间有三个测试点错误;

1070 Mooncake (25分):

思路:简单贪心;
注意:无论是D还是第二行数字都要用double存贮,否则的话测试点2错误;

1071 Speech Patterns (25分):

思路:字符串处理,遍历str,一旦检测到字母在范围内,将连续的字母保存在一个string内,将string写入map<string,int>中。最后找到map中int值最大的输出;

1072 Gas Station (30 分):
思路:重复几次Dijkstra算法就好了;
主要问题:

  1. 测试点4四舍五入问题+0.05会错,但给的测试如果不加也会错,就很迷;
  2. 还是读题问题,要求选出的是最近居民最远优先,其次找平均小再找id小;
  3. G10的问题有两位,字符串要处理一下;
1073 Scientific Notation (20 分):

思路:字符串处理;
测试点2,3:指数与小数位数相等时注意1234.问题;
测试点5,6:科学计数法小数部分位数极多,未考虑到位数问题的我一开始将前一部分直接转成double类型,虽然很方便但是精度不够;

1074 Reversing Linked List (25 分):

思路:hash数组存节点,按顺序入vector,reverse函数自动翻转,更新next就可以了;
测试点1,2:结尾next不是-1;
测试点6:包含不在起点这条链表上的节点;

1075 PAT Judge (25 分):

思路:结构体排序;
测试点2,4:

  1. 编译错误最后输出0,未提交输出-;
  2. 重复提交perfect数量;
  3. 只有全部未提交或编译错误才不输出,提交分数0的情况要输出;
  4. 我犯了rank排名的问题,如果rank放在外面,通过和前一个总分比较来输出rank的话,可能出现前一个不输出导致问题;解决方法:A. rank放到结构体;B. cmp排序那里让输出的结构体都在不输出的前面;
1076 Forwards on Weibo (30 分):

思路:广度优先算法,利用队列,无坑;

1077 Kuchiguse (20 分):

思路:每个str从后往前遍历如果相同加入结果string,一旦不相同就break,结果string翻转就好;
测试点4:测试用例是三个完全相同得字符串;

1078 Hashing (25 分):

思路:hash表二次平方探测法,注意平方探测法的hash函数(key + step * step) % size 而不是(key % size + step * step) ;
测试点1:M=1,1不是素数得特例;
注意:当平方探测法步长为tablesize的时候就可以停止

#include <iostream>
#include <cmath>
using namespace std;
int M,N;
int find_prime(int m){
    if(m==0||m==1)
        return 2;
    while(1){
        int b=1;
        for(int i=2;i<=m/i;i++){
            if(m%i==0){
                b=0;
                break;
            }
        }
        if(b)
            return m;
        m++;
    }
}
int main(){
    scanf("%d %d",&M,&N);
    int prime=find_prime(M);
    bool h[prime]={0};
    for(int i=0;i<N;i++){
        int temp,index,j=0;
        scanf("%d",&temp);
        index=temp%prime;
        while(h[(temp+(int)pow(j,2))%prime]&&j<prime){
            j++;
        }
        if(!h[(temp+(int)pow(j,2))%prime]){
            h[(temp+(int)pow(j,2))%prime]=1;
            cout<<(temp+(int)pow(j,2))%prime;
        }else
            cout<<"-";
        if(i!=N-1)
            cout<<" ";
    }
}
1079 Total Sales of Supply Chain (25 分):

思路:广度优先算法,运用队列,注意每层更新价格P*=(100+r)/100而不是P=(100+r*n)/100;

1080 Graduate Admission (30 分):

思路:结构体排序,题目真的有点长,大致意思是先按成绩排序,然后按排序完的顺序,让每个申请者的按申请学校循序录取。这里有个特例如果排名一样,即使学校满了也得录取,没有什么坑,理解题意即可;

1081 Rational Sum (20 分):

思路:格式问题,因为范围是long,分母直接相乘也可以,但主要考察求最大公约数;求最大公约数记一下这个:
long long gcd(long long a, long long b) {return b == 0 ? abs(a) : gcd(b, a % b);}

1082 Read Number in Chinese (25 分):

思路:字符串处理,注意0在字符串内的特判和字符串就是0的特判,可能以每四位为单位写函数会方便一些;

1083 List Grades (25 分):

思路:最简化最标准的结构体排序,代码打完提交一遍过;

1084 Broken Keyboard (20 分):

思路:字符串比较;

1085 Perfect Sequence (25 分):

思路:二分法查找或者双指针都可以,注意题目不要求连续,如果连续就用动态规划;

1086 Tree Traversals Again (25 分):

思路:由push入栈的顺序得到先序序列,由出栈顺序得到中序序列,推后序序列,这个类型题目考前得练习一下;

1087 All Roads Lead to Rome (30 分):

思路:在Dijkstra算法,上增加了相等时的两次特判及不同最短路径条数的计算;
测试点2:关于最短路径条数的错误,有两种方法记录路径:

  1. 在更新路径时直接计算,注意<时更新要使后一个节点路径数=前一个路径数,而==时是后一个节点路径数+=前一个路径数,两者都不能遗漏;
  2. 记录每个节点的path,最后用dfs计算,可能不容易错,多了个dfs比较麻烦我没用;
1088 Rational Arithmetic (20 分):

思路:可能主要还是考求最大公约数,溢出的处理,尽量每个数拿到先化简避免溢出;
关于测试点2的问题:
给一个测试用例,确实是很容易溢出:
e.g. -2147483648/2147483647 -2147483648/2147483645

1089 Insert or Merge (25 分):

思路:因为不论是归并还是插入排序都存在某一次的排序和下一次的排序的结果数组都是一样的情况。PAT和牛客要求插入排序输出下下次的排序结果(PAT测试点2考察);
因此插入排序用模拟的方法每走一步检验一下虽然时间复杂度上允许,但测试点2会错,检验是插入排序的条件是前n项后者大于前者,后n项两数组相等;归并排序只能用模拟的方法,可以用sort函数帮忙;

1090 Highest Price in Supply Chain (25 分):

思路:简单的层次遍历,利用queue实现,和1079相似注意更新价格;

1091 Acute Stroke (30 分):

思路:广度优先遍历,深度优先会超时,不要用递归的方法也会爆栈;

1092 To Buy or Not to Buy (20 分):

思路:字符串处理,用map记录;

1093 Count PAT’s (25 分):

思路:字符串处理,我的思路是检测到第一个A记录前后P与T的数量,新一轮遍历从第一个A开始之后每检测到一个A根据之前的PT值与经过的PT个数计算P*T值累加就是结果,时间复杂度在O(2n);

1094 The Largest Generation (25 分):

思路:又是一道标准的广度优先遍历题目,利用队列;

1095 Cars on Campus (30 分):

大量简单逻辑,等二刷重做,这一遍太乱了改了好多次,结构体都设了好多个orz;

1096 Consecutive Factors (20 分):

思路:在2-sqrt(N)的范围作为起始值i,当N%sum!=0时起始值i+1,sum为以i开始连续的乘积,一旦连续数量超过结果就更新结果;

1097 Deduplication on a Linked List (25 分):

思路:先开以地址为hash值类型为Node的hash数组存节点,开一个以key值为hash值的hash数组辨别是否删除,两个vector存两个list,最后调整next值与最后的-1;
测试点3问题:删除数组为0的情况要特判一下,不然数组越界;

1098 Insertion or Heap Sort (25 分):

思路:insertion sort与1089题一样,heap sort需要写一个将顶部为最小值的heap恢复为大根堆的函数,即从上到下遍历恢复;根据检验数组在unsorted部分执行函数即可;

1099 Build A Binary Search Tree (30 分):

思路:将key数组排序,一次深度优先遍历,一次广度优先遍历即可;

1100 Mars Numbers (20 分):

思路:进制转换+字符串处理,注意13的倍数,例13不要打tam tret,应该直接是tam,注意0的特判(测试点1);

1101 Quick Sort (25 分):

思路:特别简单的题,某数字为pivot要有两个条件:

  1. 该数在正确位置上,利用两个数组存初始数组,一个数组从小到大排序,比较两数组位置即可判断哪些数字在正确位置;
  2. 在该数前面的数都小于他,后面的数都大于他,即只要判断他比前面所有数的最大值大即可,即遍历更新一个max值,每个位置与该max值比较即可;
1102 Invert a Binary Tree (25 分):

思路:一个广度优先,一个深度优先遍历即可;

1103 Integer Factorization (30 分):

思路:递归+剪枝,递归函数search(int num,int level),num表示减去前几层平方的余数,level记录层数,在最后一层的时候特判和是否等于或小于N,每层从大到小的遍历,起始值需要剪枝,起始值需要小于sqrt(num)与上一层的底数;

1104 Sum of Number Segments (20 分):

思路:找规律:value值 * 其出现个数(与位置相关):value*((i+1)(N-i));
后两个测试点会因为100000
100000溢出可以将double类型改为long double,记得printf(“%Ld”,value);

1105 Spiral Matrix (25 分):

思路:数组从大到小排序,找到最相近的两个乘数,设控制移动数组step[4][2]={0,1,1,0,0,-1,-1,0},且设置状态0-4循环,一旦检测到下一步碰到边界或下一步已经有正数则状态+1;

1106 Lowest Price in Supply Chain (25 分):

思路:零售商系列,注意这次找最先出现没有孩子的节点,并且价格P的计算方式从(100+r*n)\100变为了(100+r)^n;

1107 Social Clusters (30 分):

思路:广度优先+套娃题,开四个数组:
vector hobby[1001]; //存每个hobby对应的人;
vector people[1001]; //存每个人对应的hobby,就是题目给的形式;
queue q; //广度优先用的队列;
int clusters[1001]={0}; 标记不同分组;
遍历clusters数组如果为0,将这个人扔到队列中广度优先开始:从people中找到队列中人的爱好,将每个爱好从hobby中找到所有有共同爱好的人,如果这个人在clusters中为0,即还没进组则更新他的组好,push到队列中;
核心代码如下:

for(int i=0;i<N;i++){
        if(clusters[i]==0){
            q.push(i);
            clusters[i]=cluster;
            while(!q.empty()){
                int size=q.size();
                for(int j=0;j<size;j++){
                    for(int k=0;k<people[q.front()].size();k++){
                        for(int l=0;l<hobby[people[q.front()][k]].size();l++){
                            if(clusters[hobby[people[q.front()][k]][l]]==0){
                                q.push(hobby[people[q.front()][k]][l]);
                                clusters[hobby[people[q.front()][k]][l]]=cluster;
                            }
                        }
                    }
                    q.pop();
                }
            }
            cluster++;
        }
    }
1108 Finding Average (20 分):

思路:字符串处理;
测试点2:当只有一个数时,最后一行numbers要改为number单数,很久前有一题也这样;
测试点3:小数点最后一位合法,如23.合法;

1109 Group Photo (25 分):

思路:逻辑题,结构体排序+顺序存到二维数组;
测试点2:每行只有1个人;

1110 Complete Binary Tree (25 分):

思路:找根,深度优先我是把整个树写到一个数组里判断数组是否连续,网络上基本都是直接找最后一个节点,确实更方便;
两个错误:

  1. 因为我要写整个数组当不是完全二叉树时数组可能为2^20次方,我的数组就开了21,故测试点2段错误。解决方法深度优先函数判断如果已经超过N就直接return,并判断是不完全二叉树;
  2. 测试点234错误:受之前一道题影响,以为都是一位数的节点,20有两位orz;
1111 Online Map (30 分):

思路:两个Dijkstra即可;
测试点4错误:找了半天,题目两个相等条件居然不一样,一个是时间最短,一个是经过路口最少!!

1112 Stucked Keyboard (20 分):

思路:由于最后输出的按照检测顺序,将字母放入vector数组,最后输出需要考虑在vector数组中的字母可能之后又判定为不是,数组仅保存次序不能全部输出;

1113 Integer Set Partition (25 分):

不知道考的啥;

1114 Family Property (25 分):

思路:并查集,合并时father统一变成小的father,最后再统计排序每个家族即可,真的狠麻烦;

1115 Counting Nodes in a BST (30 分):

思路:用静态链表存储BST,每个node中记入层数,最后统计即可;

1116 Come on! Let’s C (20 分):

思路:埃氏筛选法打印素数表,简单逻辑判断即可;

1117 Eddington Number (25 分):

题目:满足有E天骑车超过E英里的最大整数E;

1118 Birds in Forest (25 分):

思路:考察并查集,有1114题做基础,这题就是简化版;

1119 Pre- and Post-order Traversals (30 分):

感觉前中后三序的转换,逻辑比较复杂,考前要专门练习;直接贴核心代码,基本逻辑都是不断分割根、左子树、右子树;
e.g.
pre:1 2 3 4
post:2 4 3 1
其中pre的2为左根,post的3为右根,若两者相等则不唯一,即只有左子树或右子树则不唯一

void in_order(int pre_start,int pre_end,int post_start,int post_end){
    if(pre_end==pre_start){//直接输出只有一个根情况
        in.push_back(pre[pre_end]);
        return ;
    }else if(post[post_end-1]==pre[pre_start+1]){ //缺一子树,即多可能情况
        in.push_back(pre[pre_start]);
        in_order(pre_start+1,pre_end,post_start,post_end-1);
        unique=0;
        return ;
    }else{ //其他
        int index1,index2;//先找左右子树划分界限
        for(int i=post_start;i<=post_end;i++){
            if(post[i]==pre[pre_start+1])
                index1=i;
        }
        for(int i=pre_start;i<=pre_end;i++){
            if(pre[i]==post[post_end-1])
                index2=i;
        }
        in_order(pre_start+1,index2-1,post_start,index1); //进左子树
        in.push_back(pre[pre_start]); //直接输出根
        in_order(index2,pre_end,index1+1,post_end-1); //进右子树
    }
}
1120 Friend Numbers (20 分):

思路:简单的数据处理,用一个变量记录数量;

1121 Damn Single (25 分):

思路:简单hash,一个一维int数组存couple值,即couple[c1]=c2、couple[c2]=c1,一个bool数组标记是否是邀请到party的人;
注意测试点3错在输出格式%05d;

1122 Hamiltonian Cycle (25 分):

思路:满足四个条件:

  1. 除了首位没有重复;
  2. 前一个节点与后一个有路径(路径矩阵存贮);
  3. 首位节点一样;
  4. 测试节点个数>N;

注意测试点4:测试路径的节点个数可以超过200,数组开至少400才不会错误;

1123 Is It a Complete AVL Tree (30 分):

思路:avl树+一个层次遍历;可能是目前最怕的题了,又臭又长,考前一定要专门练一下;

1124 Raffle for Weibo Followers (20 分):

思路:map记录是否重复出现,vector保存顺序;

1125 Chain the Ropes (25 分):

题目:题目没理解的点是,没有读出要用光所有绳子,即改变绳子打结顺序实现最长绳子;
思路:按从小到大的顺序打结即可;

1126 Eulerian Path (25 分):

思路:计算节点度数分类+dfs判断连通图;
测试点3:需要判断是否是连通图;

1127 ZigZagging on a Tree (30 分):

思路:利用中序后序序列,用深度优先遍历标记中序的每一个节点的层数,由于中序序列同一层是有序的,之后不断遍历该序列正向反向输出每一层即可;

1128 N Queens Puzzle (20 分):

思路:皇后问题需满足两个条件:

  1. 放置棋子的行列位置之差不能相等,即不能斜着在一条线;
  2. 每个数字出现一次,即不能在同一行;
1129 Recommendation System (25 分):

题目:题目有点不理解,后来发现是根据用户每次点击的东西的编号,输出在点击当前编号前给这个用户推荐的商品orz;
思路:一个int数组记录出现次数,结构体(商品编号,出现次数)的数组记录K个要输出的商品,因为K不大于10直接每次更新完sort一下就好;

1130 Infix Expression (25 分):

思路:中序遍历加括号即可;

1131 Subway Map (30 分):

思路:广度优先原则,关于数据处理先将数据按输入保存,之后遍历该数据,将每条线路的每个station前后station加入到该车站结构体中,利用广度优先每次将pop出来的station所有可以走的路都进行判断并push即可;
测试点1345:需要将车站按4位输出;
测试点3:用了dij算法,局部最优并非全局最优;

步长相等求最短路径用广度优先!

1132 Cut Integer (20 分):

思路:简单字符串处理;
注意:浮点错误是可能为0,如100000;

1133 Splitting A Linked List (25 分):

思路:设一个node结构体分别按key值按顺序放到三个vector输出即可;
测试点段错误,后两个vector可能为空导致;
测试点大片答案错误:输出格式%05d;

1134 Vertex Cover (25 分):

思路:如果一条边的两个节点都不在测试set中,则么NO;

1135 Is It A Red-Black Tree (30 分):

思路:只需要关注红黑树的五个条件即可,利用dfs遍历;
测试点2,3错误:由于条件3、5中每条路径的黑色数量相同,是要计算没有画出来的空叶子结点的,即只有某个结点有一个空孩子,这个结点到根节点的黑色数就要相等;
用例:
1
3
1 2 -3
No

1136 A Delayed Palindrome (20 分):

思路:简单字符串处理;

1137 Final Grading (25 分):

思路:结构体排序,用一个map标记vector中是否存在该id;
四舍五入函数:cmath中round(double)函数;

1138 Postorder Traversal (25 分):

思路:本以为是简化版的前中序转后序题目,但测试点4会超时;回到递归函数中,很显然最耗时间的是在中序序列中找梗结点,于是前序序列按常规存贮,中序按hash存贮不同数字出现的位置,就能方便的找到梗结点;
代码很短附一下好了:

#include <iostream>
using namespace std;
int N,pre[50005],in[210000000];
void post_tran(int pre_l,int pre_r,int in_l,int in_r){
    if(pre_l==pre_r){
        printf("%d",pre[pre_l]);
        return ;
    }
    int root=in[pre[pre_l]];
    if(root!=in_l)
        post_tran(pre_l+1,pre_l+root-in_l,in_l,root-1);
    else
        post_tran(pre_r-in_r+root+1,pre_r,root+1,in_r);
}
int main(){
    scanf("%d",&N);
    for(int i=0;i<N;i++)
        scanf("%d",&pre[i]);
    for(int i=0;i<N;i++){
        int temp;
        scanf("%d",&temp);
        in[temp]=i;
    }
    post_tran(0,N-1,0,N-1);
}
1139 First Contact (30 分):

题意:好朋友要电话号码,A想要B,A找了同性朋友B,B找他的朋友C,C又找了同性朋友B,完成;
思路:

  1. 用二维数组标记两个人是否是朋友(邻接矩阵),用vector二维数组保存所有人的同性朋友(邻接表);
  2. 对于lovers: A和B,需要先找A的所有同性朋友C,再找B的所有同性朋友D,当C和D两人是朋友的时候则可以输出C和D;

测试点分析:
测试点12345:未按%04格式输出;
测试点345:未考虑A与B本来就是朋友,即A找了B要,B找了A,A再找B就成立了;
测试点2:未考虑0与-0问题,输入需要字符串输入;

1140 Look-and-say Sequence (20 分):

题意:大意是边看边输出,每次读前一个字符串有几个连续的几,即:
1是1个连续的1:11
11是2个连续的1:12
12是1个连续的1+1个连续的2:1121
……

1141 PAT Ranking of Institutions (25 分):

思路:结构体排序;
测试点5:每次直接乘或除累加到每个学校的score上会导致精度有问题,通过每个学校保存三个分数,最后一起乘除可以解决;

1142 Maximal Clique (25 分):

思路:遍历query的节点要求两两相连判断是不是clique,遍历没有query的节点,能否与query的节点都相连判断是不是max,其他情况则Yes;

1143 Lowest Common Ancestor (30 分):

思路:利用map标记是否存在key值;
测试点4容易超时;
由于bst的性质,判断父子关系只需要比较值的大小,由前序遍历,即每次从根开始判断直接比较大小即可。

#include <iostream>
#include <vector>
#include <map>
using namespace std;
int N,M,K,f1,f2;
vector<int> pre;
map<int,int> exist;
int main(){
    scanf("%d %d",&N,&M);
    for(int i=0;i<M;i++){
        int t;
        scanf("%d",&t);
        exist[t]=pre.size();
        pre.push_back(t);
    }
    for(int i=0;i<N;i++){
        int t1,t2;
        scanf("%d %d",&t1,&t2);
        if(exist.find(t1)==exist.end()&&exist.find(t2)==exist.end())
            printf("ERROR: %d and %d are not found.\n",t1,t2);
        else if(exist.find(t1)==exist.end())
            printf("ERROR: %d is not found.\n",t1);
        else if(exist.find(t2)==exist.end())
            printf("ERROR: %d is not found.\n",t2);
        else{
            for(int j=0;j<M;j++){
                if(pre[j]==t1){
                    printf("%d is an ancestor of %d.\n",t1,t2);
                    break;
                }else if(pre[j]==t2){
                    printf("%d is an ancestor of %d.\n",t2,t1);
                    break;
                }else if((pre[j]<t1&&pre[j]>t2)||(pre[j]>t1&&pre[j]<t2)){
                    printf("LCA of %d and %d is %d.\n",t1,t2,pre[j]);
                    break;
                }
            }
        }
    }
}
1144 The Missing Number (20 分):

简单题;

1145 Hashing - Average Search Time (25 分):

思路:需要明确hash函数的规则,碰撞冲突的规则与检测的规则;碰撞与检测都要以平方探测法并且检测中若检测到成功或0都要break,最大检测次数为max_size次;
测试点012错误:检测时检测的最大次数要<=max_size,虽然不是很理解orz;

1146 Topological Order (25 分):

思路:检测每一个数字,入度是否为0,每次更新以该数字为出发的终点的入度即可;
注意:每次检测出不是拓扑序列,不能直接break,要把后面的数字scanf完才行;

1147 Heaps (30 分):

思路:输入时用数组存贮,直接记录每个node的左右孩子的下标,比较该node的key值与左右孩子判断heap类型;再后序输出即可;

1148 Werewolf - Simple Version (20 分):

思路:枚举的思想,每次假设两匹狼,检测是否成立即可;

1149 Dangerous Goods Packaging (25 分):

思路:好像很容易超时,利用一个标记数组,每次将测试的物品及其会爆炸的物品标记1,此后若测试物品已经为1则输出No;

1150 Travelling Salesman Problem (25 分):

思路:需满足几个条件,根据每两个节点是否有直接路径,收尾节点是否相同,判断每个节点出现次数,从而判断类型;

1151 LCA in a Binary Tree (30 分):

思路:根据前序中序将树分左子树右子树,根据两个值所在左右子树位置判断类型;注意判断是否存在需要用map;

1152 Google Recruitment (20 分):

思路:写一个判断素数的函数,输入一个string,利用substr()与atoi()两个函数即可;

1153 Decode Registration Card of PAT (25 分):

思路:结构体排序的类型,题目不难分每种情况,一点点做即可。类型3利用一个标记数组+vector,数组用来判断存不存在并标记vector中位置,vector用来排序;

1154 Vertex Coloring (25 分):

思路:数组存每个节点的颜色,判断每个相邻边是否颜色相同即可;

1155 Heap Paths (30 分):

思路:首先用数组存node,更新每个node的key,left,right的值;递归函数以根右左的顺序添加到vector中,若某结点左右孩子都没有则输出vector保存的路径,输出过程中判断是否违反大根/小根堆的要求;

1156 Sexy Primes (20分)

思路:可以埃氏筛法,甚至线性筛法,20分不应该很麻烦,直接判素数函数即可。
注意:
测试点34很大
测试点3检测:比如n=10,能不能答案为11,因为5和11,11为最小sexy prime

#include <iostream>
using namespace std;
const int N=2000000010;
int n;
bool h[N];
bool is_prime(int x){
    if(x<2) return 0;
    for(int i=2;i<=x/i;i++){
        if(x%i==0){
            return 0;
        }
    }
    h[x]=1;
    return 1;
}
int main(){
    scanf("%d",&n);
    is_prime(n),is_prime(n-6),is_prime(n+6);
    if(h[n]&&(h[n-6]||h[n+6])){
        printf("Yes\n");
        if(h[n-6])
            printf("%d",n-6);
        else
            printf("%d",n);
    }else{
        for(int i=n+1;i<N;i++){
            is_prime(i),is_prime(i+6);
            if(h[i]&&h[i+6]){
                printf("No\n%d\n",i);
                return 0;
            }
            if(i<=n+6){
                if(is_prime(i-6)&&h[i]){
                    printf("No\n%d\n",i);
                    return 0;
                }
            }
        }
    }
}
1157 Anniversary (25分)

题意:若有校友alumni来,打印最老校友;若无校友来,打印最老访客
思路:map存,vector<pair<int,string>>存,可以充分利用自带函数。

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int n,m,t,res;
string temp;
unordered_map<string,int> h;
vector<pair<int,string>> alumnus;
vector<pair<int,string>> guest;
int main(){
    scanf("%d",&n);
    while(n--){
        cin>>temp;
        h[temp]=t;
    }
    scanf("%d",&m);
    while(m--){
        cin>>temp;
        t=atoi(temp.substr(6,8).c_str());
        guest.push_back({t,temp});
        if(h.count(temp)){
            res++;
            alumnus.push_back({t,temp});
        }
    }
    if(res!=0){
        sort(alumnus.begin(),alumnus.end());
        cout<<res<<endl<<alumnus[0].second<<endl;
    }else{
        sort(guest.begin(),guest.end());
        cout<<res<<endl<<guest[0].second<<endl;
    }
}
1158 Telefraud Detection (25分)

注意并查集问题
题目需要在合并时去最小值,若f数组存父亲值
f[y]=min(f[x],f[y]),f[x]=min(f[x],f[y]);
每次执行find操作,确实会让每个节点直接存根节点的值,之后查找的时间复杂度接近O(1),但仅仅是接近,不一定全是1次找到,即之后查找要用find函数而不是直接f[]找。

#include <iostream>
#include <vector>
#include <map>
#include <cstring>
using namespace std;
const int N=1010;
int k,n,m,g[N][N],f[N];
vector<int> gang;
map<int,vector<int>> gangs;
int find_f(int x){
	if(f[x]!=x) f[x]=find_f(f[x]);
    return f[x];
}

int main(){
    scanf("%d %d %d",&k,&n,&m);
    while(m--){
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        g[a][b]+=c;
    }
    for(int i=1;i<=n;i++){
        int t=0,back=0;
        for(int j=1;j<=n;j++){
            if(g[i][j]!=0&&g[i][j]<=5){
                if(g[j][i]!=0)
                    back++;
                t++;
            }
        }
        if(t>k&&back*5<=t){
            f[i]=i;
            gang.push_back(i);
        }
    }
    for(int i=0;i<gang.size();i++){
        for(int j=i+1;j<gang.size();j++){
            int x=find_f(gang[i]),y=find_f(gang[j]);
            if(g[gang[i]][gang[j]]!=0&&g[gang[j]][gang[i]]!=0){
                f[y]=min(f[x],f[y]),f[x]=min(f[x],f[y]);
            }
        }
    }
    if(gang.size()==0){
        printf("None\n");
        return 0;
    }
    for(int i=1;i<=n;i++){
        if(f[i]>0){
            gangs[find_f(i)].push_back(i);
        }
    }
    
    for(auto it=gangs.begin();it!=gangs.end();it++){
        for(int i=0;i<it->second.size();i++){
            if(i!=0)
                cout<<" ";
            cout<<it->second[i];
        }cout<<endl;
    }
}
1159 Structure of a Binary Tree (30分)

不同树遍历顺序转换:
注意在中序中找的时候for(int i=lin;i<=rin;i++),<=不是<,一个等于号扣八分,这个类型得做一道题
学会了 sscanf(string.c_str(),“%d string %d”,&a,&b);

#include <iostream>
using namespace std;
const int N=35;
int n,m,in[35],post[35],idx=-1;
string str;
struct Node{
    int level,value,left=-1,right=-1,father;
}nodes[35];
int find_index(int x){
    for(int i=0;i<n;i++){
        if(nodes[i].value==x)
            return i;
    }
}
int create(int lp,int rp,int lin,int rin,int level,int root){
    if(lp>rp||lin>rin){
        return -1;
    }
    nodes[++idx].value=post[rp];
    int a=idx;
    nodes[idx].level=level;
    nodes[idx].father=nodes[root].value;
    int t=lin;
    for(int i=lin;i<=rin;i++){
        if(in[i]==post[rp]){
            t=i;
        }
    }
    nodes[a].left=create(lp,lp+t-lin-1,lin,t-1,level+1,a);
    nodes[a].right=create(lp+t-lin,rp-1,t+1,rin,level+1,a);
    return nodes[a].value;
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&post[i]);
    for(int i=0;i<n;i++) scanf("%d",&in[i]);
    create(0,n-1,0,n-1,0,34);
    scanf("%d",&m);
    getchar();
    while(m--){
        getline(cin,str);
        if(str.find("root")<100000){
            int temp;
            sscanf(str.c_str(),"%d is the root",&temp);
            if(nodes[find_index(temp)].level==0) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("siblings")<100000){
            int temp1,temp2;
            sscanf(str.c_str(),"%d and %d are siblings",&temp1,&temp2);
            if(nodes[find_index(temp1)].father==nodes[find_index(temp2)].father&&temp1!=temp2) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("parent")<100000){
            int temp1,temp2;
            sscanf(str.c_str(),"%d is the parent of %d",&temp1,&temp2);
            if(nodes[find_index(temp2)].father==temp1) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("left")<100000){
            int temp1,temp2;
            sscanf(str.c_str(),"%d is the left child of %d",&temp1,&temp2);
            if(nodes[find_index(temp2)].left==temp1) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("right")<100000){
            int temp1,temp2;
            sscanf(str.c_str(),"%d is the right child of %d",&temp1,&temp2);
            if(nodes[find_index(temp2)].right==temp1) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("level")<100000){
            int temp1,temp2;
            sscanf(str.c_str(),"%d and %d are on the same level",&temp1,&temp2);
            if(nodes[find_index(temp1)].level==nodes[find_index(temp2)].level) printf("Yes\n");
            else printf("No\n");
        }else if(str.find("full")<100000){
            int flag=1;
            for(int i=0;i<n;i++){
                if((nodes[i].left==-1&&nodes[i].right!=-1)||(nodes[i].right==-1&&nodes[i].left!=-1)){
                    flag=0;
                }
            }
            if(flag) printf("Yes\n");
            else printf("No\n");
        }
    }
}
  • 14
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值