【PAT甲级真题整理三】1061~1090

目录

1061 Dating(20)字符串处理

1062 Talent and Virtue(25)排序

1063 Set Similarity(25)set的使用

1065 A+B and C (64bit) (20)大数溢出

1067 Sort with Swap(0, i)(25)贪心+set

1068 Find More Coins(30)01背包

1069 The Black Hole of Numbers(20)模拟

1070 Mooncake(25)排序

1071 Speech Patterns(25)Map的应用

1074 Reversing Linked List(25)链表

1075 PAT Judge(25)排序

1077 Kuchiguse(20)字符串处理

1078 Hashing(25)二次方探查法

1079 Total Sales of Supply Chain(25)建树+dfs

1081 Rational Sum(20)分数运算

1082 Read Number in Chinese(25)模拟

1083 List Grades(25)排序

1084 Broken Keyboard(20)字符串处理

1085 Perfect Sequence(25)二分

1086 Tree Traversals Again(25)树的遍历(中序先序转后序)

1090 Highest Price in Supply Chain(25)建树,dfs


1061 Dating(20)字符串处理

【题意】

给定字符串s1,s2,s3,s4,s1与s2中第一个相同的大写字母且小于等于G(因为一周只有7天),字母序号即周几,s1与s2中第二个相同的字符(可以是0-9,A-N)表示小时(0-23),s3和s4中第一个相同的字符的位置表示分钟,最后按给定格式输出即可。

【解题思路】

虽然是道水题,但是题意一定要理解清楚!!

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
char s1[maxn],s2[maxn],s3[maxn],s4[maxn];
string week[]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
int main()
{
    scanf("%s %s %s %s",s1,s2,s3,s4);
    int l1=strlen(s1),l2=strlen(s2),l3=strlen(s3),l4=strlen(s4);
    int day,index,h,m;
    for(int i=0;i<min(l1,l2);i++)
    {
        if(s1[i]==s2[i] && s1[i]>='A' && s1[i]<='G')
        {
            day=s1[i]-'A';
            index=i;
            break;
        }
    }
    //printf("%d\n",day);
    cout<<week[day]<<" ";
    for(int i=index+1;i<min(l1,l2);i++)
    {
        if(s1[i]==s2[i])
        {
            if(isdigit(s1[i]))
            {
                h=s1[i]-'0';
                break;
            }
            else if(s1[i]>='A' && s1[i]<='N')
            {
                 h=s1[i]-'A'+10;
                 break;
            }
        }
    }
    for(int i=0;i<min(l3,l4);i++)
    {
        if(s3[i]==s4[i] && isalpha(s3[i]))
        {
            m=i;
            break;
        }
    }
    printf("%02d:%02d\n",h,m);
    return 0;
}

1062 Talent and Virtue(25)排序

【题意】

根据圣人、君子、愚人、小人四个等级排序。

(1)V<L,T<L 不计入排序

(2)V>=H,T>=H 圣人

(3)V>H   L<=T<H 君子

(4)L<=V,T<H且V>T 愚人

(5)剩余

然后根据总分从大到小排序,若总分相同根据V从大到小排序,V相同根据编号从小到大排序。

【解题思路】

水题,只要理清思路就好啦!

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct People
{
    int sno,virtue,talent;
    int total;
}sage[maxn],noble[maxn],fool[maxn],rest[maxn];
bool cmp(People a,People b)
{
    if(a.total!=b.total)return a.total>b.total;
    else
    {
        return (a.virtue==b.virtue)?a.sno<b.sno:a.virtue>b.virtue;
    }
}
int main()
{
    int n,L,H,k1=0,k2=0,k3=0,k4=0;
    scanf("%d%d%d",&n,&L,&H);
    while(n--)
    {
        int sno,s1,s2;
        scanf("%d%d%d",&sno,&s1,&s2);
        if(s1<L || s2<L)continue;
        else if(s1>=H && s2>=H)
        {
            sage[k1].sno=sno;
            sage[k1].virtue=s1;
            sage[k1].talent=s2;
            sage[k1++].total=s1+s2;
        }
        else if(s1>=H && s2<H && s2>=L)
        {
            noble[k2].sno=sno;
            noble[k2].virtue=s1;
            noble[k2].talent=s2;
            noble[k2++].total=s1+s2;
        }
        else if(s1<H && s1>=L && s2<H && s2>=L && s1>=s2)
        {
            fool[k3].sno=sno;
            fool[k3].virtue=s1;
            fool[k3].talent=s2;
            fool[k3++].total=s1+s2;
        }
        else
        {
            rest[k4].sno=sno;
            rest[k4].virtue=s1;
            rest[k4].talent=s2;
            rest[k4++].total=s1+s2;
        }
    }
    sort(sage,sage+k1,cmp);
    sort(noble,noble+k2,cmp);
    sort(fool,fool+k3,cmp);
    sort(rest,rest+k4,cmp);
    printf("%d\n",k1+k2+k3+k4);
    for(int i=0;i<k1;i++)
        printf("%d %d %d\n",sage[i].sno,sage[i].virtue,sage[i].talent);
    for(int i=0;i<k2;i++)
        printf("%d %d %d\n",noble[i].sno,noble[i].virtue,noble[i].talent);
    for(int i=0;i<k3;i++)
        printf("%d %d %d\n",fool[i].sno,fool[i].virtue,fool[i].talent);
    for(int i=0;i<k4;i++)
        printf("%d %d %d\n",rest[i].sno,rest[i].virtue,rest[i].talent);
    return 0;
}

1063 Set Similarity(25)set的使用

【题意】

给定两个整数集合,它们的相似度定义为:Nc/Nt*100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
nc是两个集合的公共元素个数,nt是两个集合的所有包含的元素个数(其中元素个数表示各个元素之间互不相同)。

【解题思路】

用set存储每一组数据(因为会自动去重),然后再遍历两个所求序列,当序列a中与序列b中的元素重复时nt++,反之nc++,最后计算比例。啊我还是太嫩……虽然想到set但是没想到还能这么用!

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
vector<set<int> >v;
int main()
{
    int n,k;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int m,x;
        scanf("%d",&m);
        set<int>s;
        for(int j=0;j<m;j++)
        {
            scanf("%d",&x);
            s.insert(x);
        }
        v.push_back(s);
    }
    scanf("%d",&k);
    while(k--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int nc=0,nt=v[b-1].size();
        set<int>::iterator it;
        for(it=v[a-1].begin();it!=v[a-1].end();it++)
        {
            if(v[b-1].find(*it)==v[b-1].end())//没找到
                nt++;
            else nc++;
        }
        double ans=(double)nc/nt*100;
        printf("%.1f%%\n",ans);
    }
    return 0;
}

1065 A+B and C (64bit) (20)大数溢出

【题意】

给3个64位的整数a,b,c,判断a+b是否大于c。

【解题思路】

用long long 分3类讨论。

(1)若a>0 b<0 || a<0 b>0 那么a+b肯定在LL范围内,所以可以直接与c比较

(2)若a>0 b>0那么a+b若溢出会出现负数,如果出现负数肯定比c大,如果没有溢出可直接与c比较。

(3)若a<0 b<0那么a+b若溢出会出现非负数,如果出现非负数肯定比c小,如果没有溢出可直接与c比较。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
    int n;
    scanf("%d",&n);
    LL a,b,c;
    for(int i=1;i<=n;i++)
    {
        int flag=1;
        scanf("%lld%lld%lld",&a,&b,&c);
        LL sum=a+b;
        if((a>=0 && b<=0) || (a<=0 && b>=0))
        {
            if(sum>c)flag=1;
            else flag=0;
        }
        else if(a>=0 && b>=0)
        {
            if(sum<0)flag=1;
            else
            {
                if(sum>c)flag=1;
                else flag=0;
            }
        }
        else if(a<=0 && b<=0)
        {
            if(sum>=0)flag=0;
            else
            {
                if(sum>c)flag=1;
                else flag=0;
            }
        }
        printf("Case #%d: ",i);
        if(flag)printf("true\n");
        else printf("false\n");
    }
    return 0;
}

1067 Sort with Swap(0, i)(25)贪心+set

【题意】

给一个序列,每次只能让0和某个元素交换,问至少交换几次才能使这个序列有序。

【解题思路】

用pos数组存储每个元素对应的下标,a数组存储元素,用set存储下标与元素还没有对应的元素(不包括0),使查找更方便。

当0不在自己的位置时,将与0所在位置下标的元素交换,此时将会有1个元素归位,则在set中删除;当0在自己的位置时,随便在set中找一个元素与其交换,此时将不会有元素归位。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn],n,pos[maxn];
int main()
{
    int ans=0,index;
    set<int>s;
    set<int>::iterator it;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        pos[a[i]]=i;
        if(a[i]!=0 && a[i]!=i)
            s.insert(a[i]);
    }
    while(s.size()>0)
    {
        index=pos[0];
        if(index!=0)
        {
            int t=pos[index];
            swap(a[index],a[t]);
            pos[0]=t;
            pos[index]=index;
            s.erase(index);
        }
        else
        {
            int t=*s.begin();
            swap(a[index],a[pos[t]]);
            pos[0]=pos[t];
            pos[t]=0;
        }
        ans++;
        //printf("%d\n",s.size());
    }
    printf("%d\n",ans);
    return 0;
}

1068 Find More Coins(30)01背包

【题意】

给n种金额的硬币看是否能刚好凑出m块钱,如果不能则输出No Solution,如果可以则输出最小的、满足给定面值和的硬币序列。

【解题思路】

不难想到这是个背包问题,难点在于如何输出最小的硬币序列,需要将硬币金额先从大到小排序,然后用vis[i][j]数组dp是否选取,如果选取了就令vis为true;然后进行01背包问题求解,如果最后求解的结果不是恰好等于所需要的价值的,就输出No Soultion,否则从ans[i][j]判断选取的情况,i从n到1表示从后往前看第i个物品的选取情况,j从m到0表示从容量m到0是否选取(j = j – w[i]),把选取情况压入ans数组中。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int w[maxn],dp[maxn],vis[maxn][105],ans[maxn];
bool cmp(int a,int b)
{
    return a>b;}
int main()
{
    int n,V;
    scanf("%d%d",&n,&V);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&w[i]);
    }
    sort(w,w+n,cmp);
    memset(vis,0,sizeof(vis));
    for(int i=0;i<n;i++)
    {
        for(int j=V;j>=w[i];j--)
        {
            if(dp[j]<=dp[j-w[i]]+w[i])
            {
                dp[j]=dp[j-w[i]]+w[i];
                vis[i][j]=1;
            }

        }
    }
    if(dp[V]!=V)
    {
        printf("No Solution\n");
        return 0;
    }
    int m=V,cnt=0,i=n-1;
    while(m)
    {
        if(vis[i][m])
        {
            ans[cnt++]=w[i];
            m-=w[i];
        }
        i--;
    }
    printf("%d",ans[0]);
    for(int i=1;i<cnt;i++)
        printf(" %d",ans[i]);
    printf("\n");
    return 0;
}

1069 The Black Hole of Numbers(20)模拟

【题意】

将一个数的各位数从大到小排序得到一个数a,从小到大排序得到一个数b,当a-b=6147或0时操作结束,否则将相减得到的数一直循环上述操作。

【解题思路】

水题是水题,但是需要注意细节。

1.输入的数不一定是四位数。

2.因为我自己的程序关系,当输入数位6147和0这两种情况需要特判。

【代码】

#include<bits/stdc++.h>
using namespace std;
int a[4];
int main()
{
    int n,num=0;
    scanf("%d",&n);
    if(n==0)
    {
        printf("0000 - 0000 = 0000\n");
        return 0;
    }
    else if(n==6174)
    {
        printf("7641 - 1467 = 6174\n");
        return 0;
    }
    while(n<1000)n=n*10;
    while(n!=6174 && n!=0)
    {
        num=0;
        while(n<1000)n=n*10;
        while(n)
        {
            int x=n%10;
            a[num++]=x;
            n/=10;
        }
        //while(n<1000)n=n*10;
        sort(a,a+num);
        int sum1=0,sum2=0;
        for(int i=0;i<num;i++)
            sum1=sum1*10+a[i];
        for(int i=num-1;i>=0;i--)
            sum2=sum2*10+a[i];
        n=sum2-sum1;
        printf("%04d - %04d = %04d\n",sum2,sum1,n);
    }
    return 0;
}

1070 Mooncake(25)排序

【题意】

给n种蛋糕的库存数量以及价格,在给定需求m的情况下计算卖家的最大收益。

【解题思路】

按照价格和数量的比值从大到小排序,然后逐个取就可以了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
struct Node
{
    double num;
    double price;
    double rate;
}a[maxn];
bool cmp(Node a,Node b)
{
    return a.rate>b.rate;
}
int main()
{
    int n,x;
    scanf("%d%d",&n,&x);
    for(int i=0;i<n;i++)
        scanf("%lf",&a[i].num);
    for(int i=0;i<n;i++)
    {
        scanf("%lf",&a[i].price);
        a[i].rate=a[i].price/a[i].num;
    }
    sort(a,a+n,cmp);
    int i=0;
    double sum=0,y=x;
    for(int i=0;i<n;i++)
    {
        if(y>=a[i].num)
        {
            sum+=a[i].price;
            y-=a[i].num;
        }
        else
        {
            sum+=y/a[i].num*a[i].price;
            break;
        }
    }
    printf("%.2f\n",sum);
    return 0;
}

1071 Speech Patterns(25)Map的应用

【题意】

统计一句话中单词数量最多的单词,如果数量相同则输出字典序最小的单词和数量,单词可由字母和数字构成。

【解题思路】

这里如果用string来存储时要用getline才能识别空格。将单词存入Map中并计数。这里需要注意:

1.当遍历到最后1个字母时后面若没有其他字符必须存入map中,所以if中要加一句i==s.length()-1

2.当a字符串的长度为0时不需要存入map,如果不特判map中会存入一个空字符串

【代码】

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s,a="";
    int k=0;
    getline(cin,s);
    map<string,int>m;
    map<string,int>::iterator it;
    for(int i=0;i<s.length();i++)
    {
        if(isalpha(s[i]) || isdigit(s[i]))
        {
            s[i]=tolower(s[i]);
            a=a+s[i];
        }
        if((!isalpha(s[i]) && !isdigit(s[i])) || i==s.length()-1)
        {
            if(a.length()==0)continue;
            m[a]++;
            a="";
        }
    }
    string s2;
    int max1=-1;
    for(it=m.begin();it!=m.end();it++)
    {
        if(it->second>max1)
        {
            s2=it->first;
            max1=it->second;
        }
    }
    cout<<s2<<" "<<max1;
    return 0;
}

1074 Reversing Linked List(25)链表

【题意】

将一定长度的链表每k个长度的结点翻转,输出最后的链表。

【解题思路】

这题我感觉很坑……有以下几个注意点吧。

1.并不是所有的结点都是链表的结点,这个稍微想一下就明白了,不然告诉你首节点就没什么用了。

2.每k个长度的结点都要翻转,题中说假如链表为1→2→3→4→5→6,k=3翻转后:3→2→1→6→5→4,若k=4,4→3→2→1→5→6。

然后我刚开始没有看清第二条题意错了两个测试点,后来搜题解发现其实不用这么麻烦,直接用系统自带的reverse翻转即可(左闭右开),因为每个节点自身的地址和数据是不会变的,所以只需记录每个节点的地址直接翻转,它的next就是下个节点的地址。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e+5;
int a[maxn];
struct Node
{
    int addr;
    int data;
    int next;
}node[maxn];
int main()
{
    int address,n,k,cnt=0;
    scanf("%d%d%d",&address,&n,&k);
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        node[x].addr=x;
        scanf("%d%d",&node[x].data,&node[x].next);
    }
    while(address!=-1)
    {
        a[cnt++]=node[address].addr;
        address=node[address].next;
    }
    int i=0;
    while(k+i<=cnt)
    {
        reverse(a+i,a+i+k);
        i=i+k;
    }
    for(int i=0;i<cnt;i++)
    {
        if(i==cnt-1)
            printf("%05d %d -1\n",a[i],node[a[i]].data);
        else
            printf("%05d %d %05d\n",a[i],node[a[i]].data,a[i+1]);
    }
}

1075 PAT Judge(25)排序

【题意】

有n个用户,k个问题,m次提交,输出有过提交且不是所有提交的题目都编译没通过的用户的PAT排名,排名根据总分从大到小,总分相同则名次相同,但顺序要继续根据题目的满分数量从大到小排,若这个也相同则根据序号从小到大。

【解题思路】

虽然题目看起来就是普通的排序,但是有很多细节。

1.如果这个用户没有提交过题目,或提交的题目都是编译没通过的,则不输出排名。

2.需要输出排名的用户,编译没通过的题分数记为0,其他记最高分,没有提交过的题记“-”。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int pro[6];
struct Node
{
    int sno;
    int score[6];
    int sum=0,num=0;
    void init()
    {
        for(int i=0;i<6;i++)
            score[i]=-2;
    }
}user[maxn],u[maxn];
bool cmp(Node a,Node b)
{
    if(a.sum!=b.sum)
        return a.sum>b.sum;
    else
        return (a.num!=b.num)?a.num>b.num:a.sno<b.sno;
}
int main()
{
    int n,k,m,cnt=0;
    scanf("%d%d%d",&n,&k,&m);
    for(int i=0;i<k;i++)
        scanf("%d",&pro[i]);
    for(int i=1;i<=n;i++)
        user[i].init(),user[i].sno=i;
    for(int i=0;i<m;i++)
    {
        int x,a,b;
        scanf("%d%d%d",&x,&a,&b);
        if(user[x].score[a-1]<b)
        {
            user[x].score[a-1]=b;
            if(user[x].score[a-1]==pro[a-1])
                user[x].num++;
        }
    }
    for(int i=1;i<=n;i++)
    {
        int flag=1;
        for(int j=0;j<k;j++)
        {
            if(user[i].score[j]!=-1 && user[i].score[j]!=-2)
            {
                flag=0;
                user[i].sum+=user[i].score[j];
            }
        }
        if(!flag)
        {
            u[cnt].num=user[i].num;
            u[cnt].sno=user[i].sno;
            u[cnt].sum=user[i].sum;
            for(int j=0;j<k;j++)
            {
                if(user[i].score[j]==-1)u[cnt].score[j]=0;
                else u[cnt].score[j]=user[i].score[j];
            }
            cnt++;
        }
    }

    sort(u,u+cnt,cmp);
    int num=1,rank=1;
    printf("%d %05d %d",rank,u[0].sno,u[0].sum);
    for(int i=0;i<k;i++)
    {
        if(u[0].score[i]!=-2)
            printf(" %d",u[0].score[i]);
        else printf(" -");
    }
    printf("\n");
    for(int i=1;i<cnt;i++)
    {
        if(u[i].sum==u[i-1].sum)
            num++;
        else
        {
            rank+=num;
            num=1;
        }
        printf("%d %05d %d",rank,u[i].sno,u[i].sum);
        for(int j=0;j<k;j++)
        {
            if(u[i].score[j]!=-2)
                printf(" %d",u[i].score[j]);
            else printf(" -");
        }
        printf("\n");
    }
    return 0;
}

1077 Kuchiguse(20)字符串处理

【题意】

给定N个字符串,求他们的公共后缀,如果不存在公共后缀,就输出“nai”。

【解题思路】

因为要求后缀所以从字符串的末尾开始比较,这里用了string感觉比较方便,当字符相同时则存入s中,然后不断拿s与新输入的字符串的末尾比较,如果过程中s的长度为0,说明不存在公共后缀,输出nai,反之则输出s。

【代码】

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T,flag=0;
    scanf("%d",&T);
    string s1,s2,s="";
    getchar();
    getline(cin,s1);
    getline(cin,s2);
    int l1=s1.length()-1,l2=s2.length()-1;
    for(int i=l1,j=l2;i>=0,j>=0;i--,j--)
    {
        if(s1[i]==s2[j])
            s=s1[i]+s;
        else
             break;
    }
    T=T-2;
    if(s.length()==0)flag=1;
    while(T--)
    {
        getline(cin,s1);
        if(!flag)
        {
            s2=s;
            s="";
            l1=s1.length()-1;
            l2=s2.length()-1;
            for(int i=l1,j=l2;i>=0,j>=0;i--,j--)
            {
                if(s1[i]==s2[j])
                    s=s1[i]+s;
                else
                    break;
            }
            if(s.length()==0)flag=1;
        }
    }
    if(flag)printf("nai\n");
    else cout<<s<<endl;
    return 0;
}

1078 Hashing(25)二次方探查法

【题意】

给出散列表长和要插入的元素,将这些元素按照读入的顺序插入散列表中,其中散列函数为h(key) = key % TSize,解决冲突采用只向正向增加的二次方探查法。如果题中给出的TSize不是素数,就取第一个比TSize大的素数作为TSize。

【解题思路】

只有两个注意点。

1.找素数,这里好像不用素数筛,直接m++然后判断就可以了。

2.二次方探查法,虽然从来没有听说过这个,但是还是简单滴,就是判断index = (key + step * step) % size有没有存在,如果不用这个,最后一个测试点回过不了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int a[maxn];
int judge(int x)
{
    if(x==1)return 0;
    else if(x==2)return 1;
    for(int i=2;i<=sqrt(x);i++)
        if(x%i==0)return 0;
    return 1;
}
int main()
{
    int m,n;
    scanf("%d%d",&m,&n);
    while(!judge(m))m++;
    set<int>s;
    int cnt=0;
    for(int i=0;i<n;i++)
    {
        int x,flag=0;
        scanf("%d",&x);
        for(int j=0;j<m;j++)
        {
            int t=(x+j*j)%m;
            if(!s.count(t))
            {
                s.insert(t);
                a[cnt++]=t;
                flag=1;
                break;
            }

        }
        if(!flag)a[cnt++]=-1;
    }
    if(a[0]==-1)printf("-");
    else printf("%d",a[0]);
    for(int i=1;i<cnt;i++)
    {
        if(a[i]==-1)printf(" -");
        else printf(" %d",a[i]);
    }

    printf("\n");
    return 0;
}

1079 Total Sales of Supply Chain(25)建树+dfs

【题意】

给一棵树,在树根出货物的价格为p,然后从根结点开始每往下走一层,该层的货物价格将会在父亲结点的价格上增加r%,给出每个叶结点的货物量,求他们的价格之和。

【解题思路】

因为刚开始没读懂题目一直不知道这题目是什么鬼……这里给出样例的树。这图可能能治好你们的颈椎哈哈哈哈

采用dfs,建立结构体数组保存每一个结点的孩子结点的下标,如果没有孩子结点,就保存这个叶子结点的data(销售的量)。深度优先遍历的递归出口,即当前下标的结点没有孩子结点的时候,就把ans += data(货物量)* pow(1 + r, depth)计算货物量*价格引起的涨幅百分比。如果有孩子结点,就dfs深度优先遍历每一个孩子结点,并且在当前depth层数的基础上+1。最后输出ans * p(销售价格),即总价格。

参考柳神https://www.liuchuo.net/archives/2212

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
double price,rate,ans=0;
struct Node
{
    double data;
    vector<int>child;
}v[maxn];
void dfs(int x,int l)
{
    if(v[x].child.size()==0)
    {
        ans+=v[x].data*pow(1+rate,l);
        return;
    }
    else
    {
        for(int i=0;i<v[x].child.size();i++)
            dfs(v[x].child[i],l+1);
    }

}
int main()
{
    int n;
    scanf("%d%lf%lf",&n,&price,&rate);
    rate=rate/100;
    for(int i=0;i<n;i++)
    {
        int x,y;
        scanf("%d",&x);
        if(x==0)
            scanf("%lf",&v[i].data);
        else
        {
            for(int j=0;j<x;j++)
            {
                scanf("%d",&y);
                v[i].child.push_back(y);
            }
        }
    }
    dfs(0,0);
    printf("%.1f\n",ans*price);
    return 0;
}

1081 Rational Sum(20)分数运算

【题意】

给N个有理数(以分子/分母的形式给出),计算这N个数的总和,最后总和要以(整数 分子/分母)的形式给出。

【解题思路】

因为分子和分母的范围都是int,为了防止爆炸直接用long long即可。回归最本质的分数加法,两个分数a/b,c/d相加,分母是b和c的最小公倍数,分子是(gbs/b)*a+(gbs/d)*c。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
    while(b)
    {
        int x=a%b;
        a=b;
        b=x;
    }
    return a;
}
int main()
{
    int n;
    scanf("%d",&n);
    LL sum1=0,sum2=0;
    LL a,b,gcd1;
    scanf("%lld/%lld",&a,&b);
    gcd1=gcd(a,b);
    sum1=a/gcd1;sum2=b/gcd1;
    n--;
    while(n--)
    {
        scanf("%lld/%lld",&a,&b);
        gcd1=gcd(sum2,b);
        LL gbs=sum2*b/gcd1;
        sum1=(gbs/sum2)*sum1;
        a=(gbs/b)*a;
        sum1+=a;sum2=gbs;
        LL t=gcd(sum1,sum2);
        sum1/=t;sum2/=t;
    }
    LL r=sum1/sum2;
    int flag=0;
    if(r!=0)
    {
        printf("%lld",r);
        flag=1;
    }
    LL x=sum1-r*sum2;
    if(x!=0)
    {
        if(flag)printf(" ");
        printf("%lld/%lld",x,sum2);
    }
    if(r==0 && x==0)printf("0");
    printf("\n");
    return 0;
}

1082 Read Number in Chinese(25)模拟

【题意】

将一个数字用中文读出。

【解题思路】

把数字分为三部分读即可,即亿为单位作为一部分,万为单位作为一部分,然后是剩下的,每一部分都按照千百十来计数,然后需要注意一些细节。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=15;
string a[]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
int b[]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
string c[]={"Ge","Shi","Bai","Qian","Wan"};
int main()
{
    int n,o=0,p=0,q=0,flag=0,y,Y=0,W=0,G=0;
    scanf("%d",&n);
    if(n==0)
    {
        cout<<a[n]<<endl;
        return 0;
    }
    else if(n<0)
    {
        cout<<"Fu"<<" ";
        n=-n;
    }
    o=n/100000000;
    p=(n%100000000)/10000;
    q=n%10000;
    if(o>0)
    {
        Y=1;
        cout<<a[o]<<" Yi";
        flag=1;
    }
    for(int i=0;i<2;i++)
    {
        if(i==0)y=p;
        else y=q;
        int flag2=0;
        for(int j=3;j>=0;j--)
        {
            int x=(y/b[j])%10;
            if(i==0 && !Y && !x && !W)continue;
            if(i==1 && !W && !x && !G)continue;
            if(x>0)
            {
                if(flag2==1)
                {
                    flag==1?cout<<" "<<a[0]:cout<<a[0];
                    flag2=0;
                }
                if(j!=0)flag==1?cout<<" "<<a[x]<<" "<<c[j]:cout<<a[x]<<" "<<c[j];
                else flag==1?cout<<" "<<a[x]:cout<<a[x];
                flag=1;
            }
            else flag2=1;
            W=1;G=1;
        }
        if(i==0 && W)cout<<" "<<c[4];
    }
    printf("\n");
    return 0;
}

1083 List Grades(25)排序

【题意】

给n个人的名字科目和成绩,再给一个成绩的上界和下届,按降序输出在界限之内的人的名字科目,如果没有人在这个范围内则输出“NONE”。

【解题思路】

简单的排序,注意细节即可。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e+5;
struct Node
{
    string name;
    string cno;
    int grade;
}student[maxn];
bool cmp(Node a,Node b)
{
    return a.grade>b.grade;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        cin>>student[i].name>>student[i].cno>>student[i].grade;
    int l,r;
    scanf("%d%d",&l,&r);
    sort(student,student+n,cmp);
    if(student[0].grade<l || student[n-1].grade>r)
        printf("NONE\n");
    else
    {
        for(int i=0;i<n;i++)
        {
            if(student[i].grade>=l && student[i].grade<=r)
                cout<<student[i].name<<" "<<student[i].cno<<endl;
        }
    }
    return 0;
}

1084 Broken Keyboard(20)字符串处理

【题意】

给两个字符串,字符串1为本来想打的字符串,字符串2为键盘坏了几个键后打出的字符串,求键盘坏了哪几个键,并输出大写字符。

【解题思路】

用set记录字符串2中出现的字符,然后遍历字符串1,若字符串1中的字符在set中没有出现过,就说明这个键坏了,但是要注意不能输出重复的键,所以要再用一个set记录坏了的键。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
char a[maxn],b[maxn];
int main()
{
    scanf("%s",a);
    set<char>s;
    set<char>s2;
    char x;
    scanf("%s",b);
    for(int i=0;i<strlen(b);i++)
    {
        if(isalpha(b[i]))
            x=toupper(b[i]);
        else x=b[i];
        if(!s.count(x))
            s.insert(x);
    }
    for(int i=0;i<strlen(a);i++)
    {
        if(isalpha(a[i]))
            x=toupper(a[i]);
        else x=a[i];
        if(!s.count(x) && !s2.count(x))
        {
            s2.insert(x);
            printf("%c",x);
        }
    }
    printf("\n");

}

1085 Perfect Sequence(25)二分

【题意】

给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列。现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列。输入第一行给出两个正整数N(输入正数的个数)和p(给定的参数),第二行给出N个正整数。在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

【解题思路】

先将数组排序,然后用一下upper_bound找第一个大于最小值的元素的位置,更新最大长度。这里不能用lower_bound(),因为如果查找第一个大于等于最小值的元素的位置的话,当序列中有等于这个元素时,数组下标要-i+1,但是没有的话会返回一个大于这个元素的位置,就不需要+1了,所以还是用upper_bound()比较安全。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
LL a[maxn];
int main()
{
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=0;i<n;i++)
        scanf("%lld",&a[i]);
    sort(a,a+n);
    if(n==0)
    {
        printf("0\n");
        return 0;
    }
    int maxlen=1;
    for(int i=0;i<n;i++)
    {
        LL x=a[i]*p;
        int t=upper_bound(a,a+n,x)-(a+i);
        maxlen=max(t,maxlen);
    }
    printf("%d\n",maxlen);
    return 0;
}

 

1086 Tree Traversals Again(25)树的遍历(中序先序转后序)

【题意】

用栈的push、pop操作给出一棵二叉树的中序遍历顺序,求这棵二叉树的后序遍历。

【解题思路】

对于push x操作:
1).第一个push肯定是根节点root。
2).根据child变量,建立父节点v与x的父子关系。
3).由于是中序遍历,所以接下来的节点必定是v的left(如果有的话),child=left,v=x;
4).然后进行push操作

对于pop操作:
1).根据中序遍历性质,可知接下来的节点必定是pop节点的右孩子(如果有的话),child=rightv,v=s.top()
2).进行pop操作。

转自http://www.cnblogs.com/chenxiwenruo/p/6388909.html

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
const int LEFT=1,RIGHT=-1;
int flag=0;
struct Node
{
    int left=-1;
    int right=-1;
}node[maxn];
void post(int x)
{
    if(x==-1)return;
    post(node[x].left);
    post(node[x].right);
    if(!flag)
    {
        printf("%d",x);
        flag=1;
    }
    else printf(" %d",x);
}
int main()
{
    int n,root=-1,child=LEFT,v=-1;
    stack<int>s;
    scanf("%d",&n);
    for(int i=0;i<2*n;i++)
    {
        char a[5];
        scanf("%s",a);
        if(a[1]=='u')
        {
            int x;
            scanf("%d",&x);
            if(root==-1)root=x;
            else
            {
                if(child==LEFT)node[v].left=x;
                else node[v].right=x;
            }
            v=x;
            child=LEFT;
            s.push(x);
        }
        else
        {
            child=RIGHT;
            v=s.top();
            s.pop();
        }
    }
    post(root);
    printf("\n");
    return 0;
}

1090 Highest Price in Supply Chain(25)建树,dfs

【题意】

给一棵树,在树根处货物的价格为p,然后每往下走一层,价格增加r%,求所有叶子结点的最高价格,以及这个价格的叶子结点个数。

【解题思路】

和1079思路是一样滴~但是我不明白为什么中途就更新ans和最后算ans不一样,中途算(就是我注释的那句)会有一个测试点错误,难道是精度丢失?希望有大佬能够解答的话可以告诉我~感谢!!

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
double price,rate,ans=0;
int cnt=0,maxlenth=0;
vector<int>v[maxn];
void dfs(int x,int l)
{
    if(v[x].size()==0)
    {
        if(l>maxlenth)
        {
            maxlenth=l;
            //ans=max(ans,pow(1+rate/100,l));
            cnt=1;
        }
        else if(l==maxlenth)
                cnt++;
        return;
    }
    for(int i=0;i<v[x].size();i++)
        dfs(v[x][i],l+1);
}
int main()
{
    int n,root;
    scanf("%d%lf%lf",&n,&price,&rate);
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        if(x==-1)root=i;
        else
            v[x].push_back(i);
    }
    dfs(root,0);
    printf("%.2f %d\n",pow(1+rate/100,maxlenth)*price,cnt);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/81841389
今日推荐