PAT甲级

PAT Note

1. B1001 害死人不偿命的(3n+1)猜想

1. 题目描述

卡拉兹(Callatz)猜想:

对任何一个自然数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹得学生们无心学业,一心只证(3n+1),以至于有人说这是一个阴谋,卡拉兹是在蓄意延缓美国数学界教学与科研的进展……

我们今天的题目不是证明卡拉兹猜想,而是对给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?

输入格式:

每个测试输入包含1个测试用例,即给出自然数n的值。

输出格式:

输出从n计算到1需要的步数。

输入样例:

3

输出样例:

5

2. 分析

偶数:n = n/2 k++

奇数:n = (3n+1)/2 k++

计算当n=1 的时候,k为多少?

定义一个递归函数,终止条件是n==1,使用全局变量k记录

3 代码

int Find(int n,int &k);
int main(){
    int n;
    cin>>n;
    int k= 0;
    cout<<Find(n,k);
    return 0;
}
//主要内容是计算递归函数调用次数
//一定要注意通过引用传入变量
//注意return Fun() 进行递归调用
int Find(int n,int &k){

    if(n==1)
        return k;
    k++;
    if(n%2==0){
        return Find(n/2,k);
    } else{
        return Find( (3*n+1)/2,k);
    }
}

3.1 更加简洁的思路

#include <iostream>
using namespace std;
int main() {
    int n, count = 0;
    cin >> n;
    while (n != 1) {
        if (n % 2 != 0) n = 3 * n + 1;
        n = n / 2;
        count++;
    }//直接设计行走路径,计算行走步伐
    cout << count;
    return 0;
}

4. 收获

主要内容是计算递归函数调用次数

一定要注意通过引用传入变量

注意return Fun() 进行递归调用

直接设计行走路径,计算行走步伐

2. B1032 挖掘机技术哪家强

1. 题目描述

为了用事实说明挖掘机技术到底哪家强,PAT组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

输入格式

输入在第****1行给出不超过$10^5$ 的正整数N,即参赛人数。随后N行,每行给出一位参赛者的信息和成绩,包括其所代表的学校的编号(从1开始连续编号)、及其比赛成绩(百分制),中间以空格分隔。

输出格式

在一行中给出总得分最高的学校的编号、及其总分,中间以空格分隔。题目保证答案唯一,没有并列。

输入样例

6

3 65

2 80

1 100

2 70

3 40

3 0

输出样例

2 150

2. 分析

建立一个数组,0,1,2,3,初始化为0 ,对应位置为 分数

之后再输出最大值及其所在的位置即可

3 代码

这个代码是错误的,有一个用例测试不出来,问题未知

 
int main(){
    int n;
    cin>>n;
    int score[n+1];
    memset(score,0,sizeof (score));
    for(int i=0;i<n;i++){
        int num,scor;
        cin>>num>>scor;
        score[num]+= scor;

    }

//    for (int i=0;i<n+1;i++){
//        cout<<score[i]<<" ";
//    }
    //找数组的最大值和对应的位置
    int max = -1;
    int pos = -1;
    for (int i=0;i<n+1;i++){
        if(score[i]>max){
            max = score[i];
            pos = i;
        }
    }
    cout<<pos<<" "<<max;
    return 0;
}

3.1 更加简洁的思路

#include <iostream>
#include <vector>
using namespace std;
int main() {
    int N;
    cin >> N;
    vector<int> a(N + 1);
    int num, score;
    for (int i = 0; i < N; i++) {
        cin >> num >> score;
        a[num] += score;
    }
    int max = a[1], pos= 1;
    for (int i = 2; i <= N; i++) {
        if (max < a[i]) {
            max = a[i];
            t = i;
        }
    }
    cout << t << " " << max;
    return 0;
}

4. 收获

1.利用数组作为字典:Score[ID] = score

2.数组的最值查找和位置返回

 if (max < a[i]) {
            max = a[i];
            pos = i;
        }

3.数组: vector a(N + 1);

3. A1006 Sign In and Sign Out

1. 题目描述

At the beginning of every day, the first person who signs in the computer room will unlock the door, and the last one who signs out will lock the door. Given the records of signing in’s and out’s, you are supposed to find the ones who have unlocked and locked the door on that day.

Input Specification:

Each input file contains one test case. Each case contains the records for one day. The case starts with a positive integer M, which is the total number of records, followed by M lines, each in the format:

ID_number Sign_in_time Sign_out_time

where times are given in the format HH:MM:SS, and ID number is a string with no more than 15 characters.

Output Specification:

For each test case, output in one line the ID numbers of the persons who have unlocked and locked the door on that day. The two ID numbers must be separated by one space.

Note: It is guaranteed that the records are consistent. That is, the sign in time must be earlier than the sign out time for each person, and there are no two persons sign in or out at the same moment.

Sample Input:

3

CS301111 15:30:28 17:00:10

SC3021234 08:00:00 11:25:25

CS301133 21:45:00 21:58:40

Sample Output:

SC3021234 CS301133

2. 分析

如何比较时间早晚?

转换为秒数,秒数大的晚,秒数小的早

如何存储数据?

不用存储,在读入的过程中就比较

3 代码

//
// Created by Administrator on 2023/2/4.
//
#include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    int minn = INT_MAX, maxn = INT_MIN;
    int n;
    scanf("%d", &n);
    string lockID, unlockID;

    for (int i = 0; i < n; i++) {
        string id;
        cin >> id;
        int h1, m1, s1, h2, m2, s2;//在输入的时候就将数据分割

        scanf("%d:%d:%d %d:%d:%d", &h1, &m1, &s1, &h2, &m2, &s2);
//       转换时间为秒数,先将时转为分,再转为秒
        int early = (h1 * 60 + m1) * 60 + s1;
        int late = (h2 * 60 + m2) * 60 + s2;
        if (early < minn) {
//      别忘记替换最值了!
            minn = early;
            unlockID = id;
        }
        if (late > maxn) {
            maxn = late;
            lockID = id;
        }
    }


    cout << unlockID << " " << lockID;

    return 0;
}

3.1 更加简洁的思路

#include<iostream>
using namespace std;

int main()
{
    int M;
    cin>>M;
    string earlist_signin="999",latest_signout="000";
    string earlist,latest;
    while(M--){
        string s1,s2,s3;
        cin>>s1>>s2>>s3;
        if(s2<earlist_signin){
            earlist_signin=s2;
            earlist=s1;
        }
        if(s3>latest_signout){
            latest_signout=s3;
            latest=s1;
        }
    }
    cout<<earlist<<' '<<latest;
}

4. 收获

如何比较时间早晚?

1.秒数

2.字符串比较

如何存储数据?

最值查找

1.minn = INT_MAX,maxn = INT_MIN;//需要引入climits头文件

$\textcolor{red}{遇到数据,就要确认范围}$,一般测试不通过都可能在此点上

4. B1036 跟奥巴马一起编程(15)

1. 题目描述

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入格式

输入在一行中给出正方形边长N(3<=N<=20)和组成正方形边的某种字符C,间隔一个空格。

输出格式

输出由给定字符C画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的50%(四舍五入取整)。

输入样例

10 a

输出样例

aaaaaaaaaa

a a

a a

a a

aaaaaaaaaa

2. 分析

边长为变量:len

第一行:len 个 c直接输出

进入for循环 为len/2 -2 次

输出c

进入for循环 为len/2-2次

输出“ ”

输出c

最后一行:len 个 c直接输出

3 代码

#include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    int len;
    char c;

    scanf("%d %c",&len,&c);
    for(int i=0;i<len;i++)  //第一行
    {
        printf("%c",c);
    }
    printf("\n");
    //中间行
    float x = round(((float)len)/2)-2;
    for(int i=0;i<round(((float)len)/2)-2;i++)
    {
//        第一列
        printf("%c",c);
//        中间列
        for(int j=0;j< len-2;j++)
        {
            printf(" ");
        }
//        最后一列
        printf("%c\n",c);
    }
    for(int i=0;i<len;i++)  //最后一行
    {
        printf("%c",c);
    }
    printf("\n");
    return 0;
}

3.1 更加简洁的思路

 

4. 收获

四舍五入

注意转为(float) len

然后round()

5. A1031. Hello World for U (20)

1. 题目描述

Given any string of N (>=5) characters, you are asked to form the characters into the shape of U. For example, “helloworld” can be printed as:

h d

e l

l r

lowo

That is, the characters must be printed in the original order, starting top-down from the left vertical line with n1 characters, then left to right along the bottom line with n2 characters, and finally bottom-up along the vertical line with n3 characters. And more, we would like U to be as squared as possible — that is, it must be satisfied that n1 = n3 = max { k| k <= n2 for all 3 <= n2 <= N } with n1 + n2 + n3 – 2 = N.

Input Specification:

Each input file contains one test case. Each case contains one string with no less than 5 and no more than 80 characters in a line. The string contains no white space.

Output Specification:

For each test case, print the input string in the shape of U as specified in the description.

sample Input:

helloworld!

Sample Output:

h !

e d

l l

lowor

2. 分析

要确定边长len是多少

长度为N

n1 = n3 = max { k| k <= n2 for all 3 <= n2 <= N }

n1 + n2 + n3 – 2 = N

如何求解n1,n2,n3?

==此分类讨论为核心==

分类讨论:在满足等式的条件下,要让n1尽可能的大

如果N+2可以被3整除,那么 n1 == n2 == n3

如果(N+2)%3 ==1 那么多出来一个,给n2

n1 = (N+2-1)/3

n2=n1+1

如果(N+2)%3 ==2 那么多出来两个

只能全给n2

n1 = (N+2-2)/3

n2 = n1+2

确定n1,n2,n3以后,进行U行打印

进行循环:循环

首先是取第1个字母

中间要隔n2-2个空格

然后是最后一个字母

这样比较复杂

还是应该初始化一个数组,为空格

进行U行填充,先进行第一列填充,再进行最后一行填充,在进行最后一列填充

3 代码

#include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    char c[81], u[30][30];
    scanf("%s", c);
    memset(u, ' ', sizeof(u));
    int n1, n2, n3, n;
    n = strlen(c) + 2;
    n1 = n / 3;
    n2 = n / 3 + n % 3;
    n3 = n1;
//    设置一个index变量,用于按序索引c数组
//    填充u行数组
    int index = 0;
    int i, j, k;
    for (i = 0; i < n1; i++) {
        u[i][0] = c[index++];
    }
    for (j = 1; j < n2 - 1; j++) {
        u[i-1][j] = c[index++];
    }
    for (k = i; k >0; k--) {
        u[k-1][j] = c[index++];
    }
//    按行输出
    for (int i = 0; i < n1; i++) {
        for (int j = 0; j < n2; j++) {
            printf("%c", u[i][j]);
        }
        printf("\n");
    }

    return 0;
}

3.1 更加简洁的思路

 

4. 收获

1.如何计算n1的值?

应当进行数学直觉上的分析,一般不会太复杂,一般都是除法与取余

    n1 = n / 3;
    n2 = n / 3 + n % 3;
    n3 = n1;

也可以进行枚举

2.如何进行U行输出

先存放于数组中,因为数组可以按行按列,比较方便

注意i,j的取值

6. A1058 A+B in Hogwarts (20)

1. 题目描述

If you are a fan of Harry Potter, you would know the world of magic has its own currency system -- as Hagrid explained it to Harry, "Seventeen silver Sickles to a Galleon and twenty-nine Knuts to a Sickle, it's easy enough." Your job is to write a program to compute A+B where A and B are given in the standard form of Galleon.Sickle.Knut (Galleon is an integer in [0,107], Sickle is an integer in [0, 17), and Knut is an integer in [0, 29)).

Input Specification:

Each input file contains one test case which occupies a line with A and B in the standard form, separated by one space.

Output Specification:

For each test case you should output the sum of A and B in one line, with the same format as the input.

Sample Input:

3.2.1 10.16.27

Sample Output:

14.1.28

2. 分析

Galleon.Sickle.Knut (Galleon is an integer in [0,$10^7$], Sickle is an integer in [0, 17), and Knut is an integer in [0, 29)).

进制转化

两种思路:一种是在魔法学院按照进位法进行计算

一种是转为人间,用十进制计算,然后再转为魔法学院的进制

那种更简单呢,都可以,这里使用第一种

三个变量:Galleon,Sickle,Knut

分别存储,然后按照进制相加,如果超出范围,则高位+1,本位取余

3 代码

代码没有AC,有一个用例过不去

88.16.28 88.16.28

#include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    int Galleon1,Sickle1,Knut1,Galleon2,Sickle2,Knut2,Galleon=0 ,Sickle=0 ,Knut=0 ;
    scanf("%d.%d.%d %d.%d.%d",&Galleon1,&Sickle1,&Knut1,&Galleon2,&Sickle2,&Knut2);
//    kunt
    if(Knut1+Knut2<29)
    {
        Knut += (Knut1+Knut2);
    }
    else{
        Sickle += ((Knut1+Knut2)/29);
        Knut += ((Knut1+Knut2)%29);
    }
//    Sickle
    if(Sickle1+Sickle2<17)
    {
        Sickle += Sickle1+Sickle2;
    }
    else{
        Galleon += (Sickle1+Sickle2)/17;
        Sickle += (Sickle1+Sickle2)%17;
    }
//    Galleon
    Galleon+= (Galleon1+Galleon2);
    printf("%d.%d.%d",Galleon,Sickle,Knut);
    return 0;
}

3.1 更加简洁的思路

 #include <iostream>
using namespace std;
int main() {
    int a1, b1, c1, a2, b2, c2, a, b, c;
    scanf("%d.%d.%d %d.%d.%d", &a1, &b1, &c1, &a2, &b2, &c2);
    c = c1 + c2;
    b = b1 + b2 + c / 29; c = c % 29;
    a = a1 + a2 + b / 17; b = b % 17;
    printf("%d.%d.%d\n", a, b, c);
    return 0;
}

4. 收获

1.对于变量要注意赋初始值,否则很容易出现异常错误

2.对于进制转化,要利用好取余操作和整除操作,不用加入判断语句,直接进行计算即可

7. A1061 Dating

1. 题目描述

Sherlock Holmes received a note with some strange strings: Let's date! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm. It took him only a minute to figure out that those strange strings are actually referring to the coded time Thursday 14:04 -- since the first common capital English letter (case sensitive) shared by the first two strings is the 4th capital letter D, representing the 4th day in a week; the second common character is the 5th capital letter E, representing the 14th hour (hence the hours from 0 to 23 in a day are represented by the numbers from 0 to 9 and the capital letters from A to N, respectively); and the English letter shared by the last two strings is s at the 4th position, representing the 4th minute. Now given two pairs of strings, you are supposed to help Sherlock decode the dating time.

Input Specification:

Each input file contains one test case. Each case gives 4 non-empty strings of no more than 60 characters without white space in 4 lines.

Output Specification:

For each test case, print the decoded time in one line, in the format DAY HH:MM, where DAY is a 3-character abbreviation for the days in a week -- that is, MON for Monday, TUE for Tuesday, WED for Wednesday, THU for Thursday, FRI for Friday, SAT for Saturday, and SUN for Sunday. It is guaranteed that the result is unique for each case.

Sample Input:

3485djDkxh4hhGE 
2984akDfkkkkggEdsb 
s&hgsfdk 
d&Hyscvnm

Sample Output:

THU 14:04

2. 分析

题目非常难以理解,主要在于转换过程挺复杂

首先需要找到前两个字符串中 两个相同的字母或数字

这样就可以得到Day HH

然后再看最后两个字符串,找到相同的字母所在的位置,代表分钟数

应该如何找到相同的字母呢?

直接对比即可

流程:

对比找字母

对比找位置

3 代码

 #include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    string a,b,c,d;
    cin>>a>>b>>c>>d;
    int j;
//    对比两个字符串,找到相同的字母
    char t[4];
    for(int i=0;i<min(a.length(),b.length());i++)
    {
        if(a[i]==b[i] && a[i]>='A'&& a[i]<='G'){
            t[0] = a[i];
             j = i+1;
            break;
        }

    }
    for(;j<min(a.length(),b.length());j++)
    {
        if(a[j]==b[j] && (a[j]>='A'&& a[j]<='N'|| isdigit(a[j])) ){
            t[1] = a[j];
            break;
        }

    }
    for(int i=0;i<min(c.length(),d.length());i++)
    {
        if(c[i]==d[i] && isalpha(c[i])){
            t[2] = i;

            break;
        }

    }
//    对t进行转义
    string week[7]={"MON ", "TUE ", "WED ", "THU ", "FRI ", "SAT ", "SUN "};

    string Day = week[t[0]-'A'];
    int h = isdigit(t[1])? t[1]-'0': t[1]-'A'+10;
    int m = t[2];
    cout<<Day;
    printf("%02d:%02d", h, m);

    return 0;
}

3.1 更加简洁的思路

 

4. 收获

1.一定注意判断条件括号

2.isdigit(),isalpha()

8. 1005 Spell It Right

1. 题目描述

Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English.

Input Specification:

Each input file contains one test case. Each case occupies one line which contains an $N(≤10^{100})$.

Output Specification:

For each test case, output in one line the digits of the sum in English words. There must be one space between two consecutive words, but no extra space at the end of a line.

Sample Input:

12345

Sample Output:

one five

2. 分析

  • 分离数字

  • 计算和

  • 将数字转为 英文

  • 要提取个位,十位,百位,千位等,然后输出相应的英文单词

  • 关于提取方法:转为字符串,to_string(),即可进行提取

3 代码

 #include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    string N;
    cin>>N;
    long sum=0;
    for(int i=0;i<N.length();i++)
    {
        sum += (int)(N[i]-'0'); //N[i]是个字符
    }
//   分离个位,十位
    string num2Eng[100] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
    string sum2Eng = to_string(sum);
    for(int i=0;i<sum2Eng.length()-1;i++)
    {
        cout<<num2Eng[sum2Eng[i]-'0']<<" ";
    }
    cout<< num2Eng[sum2Eng[sum2Eng.length()-1]-'0'];

    return 0;
}

3.1 更加简洁的思路

 

4. 收获

字符串数组和字符数组是不一样的

字符串数组:

string num2Eng[100] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

提取数字个位,十位,百位的方法可以将其转为 字符串

to_string()

9. A1082 Read Number in Chinese

1. 题目描述

Given an integer with no more than 9 digits, you are supposed to read it in the traditional Chinese way. Output Fu first if it is negative. For example, -123456789 is read as Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu. Note: zero (ling) must be handled correctly according to the Chinese tradition. For example, 100800 is yi Shi Wan ling ba Bai.

Input Specification:

Each input file contains one test case, which gives an integer with no more than 9 digits.

Output Specification:

For each test case, print in a line the Chinese way of reading the number. The characters are separated by a space and there must be no extra space at the end of the line.

Sample Input 1:

-123456789

Sample Output 1:

Fu yi Yi er Qian san Bai si Shi wu Wan liu Qian qi Bai ba Shi jiu

Sample Input 2:

100800

Sample Output 2:

yi Shi Wan ling ba Bai

2. 分析

  • 转为字符串处理

  • 千位以下,赋予位权 千百十

  • 万位以上亿以下,最后加一个万

  • 亿以上,加一个亿

  • -1,2345,6789

  • 也就是四位为一个整体,后面响应的加上万 亿

  • 10,0800 如果首位为0 ,那么前面加上 ling

一个字符串数组,进行拼接

yi Shi Wan ling ba Bai ling

yi Shi Wan ling ba Bai

如果个位是0,不加,如果ling在千位,百位,十位,那么都不加

3 代码

仍有一个测试通不过

 #include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>

using namespace std;

int main() {
    string numStr;
    cin>>numStr;
    string chinnum[100]={};
    int index=0;
    int weight=0;
    int ii=0;
    bool flag= false;
    string num2Chi[10]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
    string chiWeight[6]={"","Shi","Bai","Qian","Wan","Yi"};
    for(int i=numStr.length()-1;i>=0;i--)
    {
        if(  numStr[i]=='-'){
            chinnum[index++] ="Fu";
        }
else{

//        取前四位 6789
        if(ii==4)//已经到了第二个四位了
        {
            chinnum[index++] =chiWeight[4];
        }
//        -123456789
        if(ii==8)//已经到了第二个四位了
        {
            chinnum[index++] =chiWeight[5];
        }
        if(weight==4)
        {
            weight=0;
        }
        if(weight!=0)
        {
            if(numStr[i]-'0'== 0 )
            {
                if(flag)
                {
                    weight++;

                }
                else
                {
                    weight++;
                    chinnum[index++] =num2Chi[ numStr[i]-'0'];
                }
//                chinnum[index++] =chiWeight[weight++];

            } else{
                flag = false;
                chinnum[index++] =chiWeight[weight++];
                chinnum[index++] =num2Chi[ numStr[i]-'0'];
            }

        }
        else
        {
            weight++;
            if(numStr[i]-'0'==0)
            {
                flag = true;
            } else{
                chinnum[index++] =num2Chi[ numStr[i]-'0'];
            }

        }


        ii++;
        }

    }
    for(int i=index-1;i>0 ;i--)
    {
        cout<<chinnum[i]<<" ";
    }
    cout<<chinnum[0];

    return 0;
}

3.1 更加简洁的思路

 #include <iostream>
#include <string>
#include <vector>
using namespace std;
string num[10] = { "ling","yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu" };
string c[6] = { "Ge","Shi", "Bai", "Qian", "Yi", "Wan" };
int J[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
vector<string> res;
int main() {
    int n;
    cin >> n;
    if (n == 0) {
        cout << "ling";
        return 0;
    }
    if (n < 0) {
        cout << "Fu ";
        n = -n;
    }
    int part[3];
    part[0]= n / 100000000; 
    part[1]= (n % 100000000) / 10000;
    part[2] = n % 10000;
    bool zero = false; //是否在非零数字前输出合适的ling
    int printCnt = 0; //用于维护单词前没有空格,之后输入的单词都在前面加一个空格。
    for (int i = 0; i < 3; i++) {
        int temp = part[i]; //三个部分,每部分内部的命名规则都一样,都是X千X百X十X
        for (int j = 3; j >= 0; j--) {
            int curPos = 8 - i * 4 + j; //当前数字的位置
            if (curPos >= 9) continue; //最多九位数
            int cur = (temp / J[j]) % 10;//取出当前数字
            if (cur != 0) {
                if (zero) {
                    printCnt++ == 0 ? cout<<"ling" : cout<<" ling";
                    zero = false;
                }
                if (j == 0)
                    printCnt++ == 0 ? cout << num[cur] : cout << ' ' << num[cur]; //在个位,直接输出
                else                             
                    printCnt++ == 0 ? cout << num[cur] << ' ' << c[j] : cout << ' ' << num[cur] << ' ' << c[j]; //在其他位,还要输出十百千
            } else {
                if (!zero && j != 0 && n / J[curPos] >= 10) zero = true;   //注意100020这样的情况
            }
        }
        if (i != 2 && part[i]>0) cout << ' ' << c[i + 4]; //处理完每部分之后,最后输出单位,Yi/Wan
    }
    return 0;
}

4. 收获

  • 这题太难了

  • 难点在于如何组装字符串,千位百位如何加入

  • 第二个难点在于如何处理ling条件

  • 逻辑要清晰,要写每一个分支的注释,否则就看不懂了

10. A1016

1. 题目描述

A long-distance telephone company charges its customers by the following rules:

Making a long-distance call costs a certain amount per minute, depending on the time of day when the call is made. When a customer starts connecting a long-distance call, the time will be recorded, and so will be the time when the customer hangs up the phone. Every calendar month, a bill is sent to the customer for each minute called (at a rate determined by the time of day). Your job is to prepare the bills for each month, given a set of phone call records.

Input Specification:

Each input file contains one test case. Each case has two parts: the rate structure, and the phone call records.

The rate structure consists of a line with 24 non-negative integers denoting the toll (cents/minute) from 00:00 - 01:00, the toll from 01:00 - 02:00, and so on for each hour in the day.

The next line contains a positive number N (≤1000), followed by N lines of records. Each phone call record consists of the name of the customer (string of up to 20 characters without space), the time and date (MM:dd:HH:mm), and the word on-line or off-line.

For each test case, all dates will be within a single month. Each on-line record is paired with the chronologically next record for the same customer provided it is an off-line record. Any on-line records that are not paired with an off-line record are ignored, as are off-line records not paired with an on-line record. It is guaranteed that at least one call is well paired in the input. You may assume that no two records for the same customer have the same time. Times are recorded using a 24-hour clock.

Output Specification:

For each test case, you must print a phone bill for each customer.

Bills must be printed in alphabetical order of customers' names. For each customer, first print in a line the name of the customer and the month of the bill in the format shown by the sample. Then for each time period of a call, print in one line the beginning and ending time and date (dd:HH:mm), the lasting time (in minute) and the charge of the call. The calls must be listed in chronological order. Finally, print the total charge for the month in the format shown by the sample.

Sample Input:

10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line

 

Sample Output:

CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

2. 分析

  1. 首先需要对其按照时间排序 (不行的,先按照姓名,再按照时间排序),然后配对online,offline

  1. 配对规则是 一个online 下面必须是一个offline ,否则这俩都失效,直到配对成功

  1. 然后计算间隔时间,由于不同的时间有不同的价格,因此需要对每个小时进行分割

3 代码

#include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>
#include<map>
#include<vector>

using namespace std;

struct node{
    string name;
    int status,month,time,day,hour,minute;
}; //信息结构体变量

bool cmp(node a,node b)
{
    if(a.name!=b.name)//先按name 升序
    {
        return a.name<b.name;
    } else

    {
//        再按照 时间升序

            return a.time<b.time;

    }
//    return a.name != b.name ? a.name < b.name : a.time < b.time;

}
double billFromZero(node call, int rate[])
{
//    计算费用(这里计算总费用,间隔费用相减即可!)
//    01:06:01
    double total = rate[call.hour] * call.minute + rate[24] * 60 * call.day; //min + day
    for (int i = 0; i < call.hour; i++)
        total += rate[i] * 60; //hour
    return total / 100.0;


}
int main() {
    //读入文件
    int rate[25] = {0}, n;
    for (int i = 0; i < 24; i++) {
        scanf("%d", &rate[i]);
        rate[24] += rate[i]; //一天的汇率汇总
    }
    scanf("%d", &n);
    // 结构体数组
    vector<node>data(n);
    //往结构体数组里面存入信息
    for(int i=0;i<n;i++)
    {
        cin>>data[i].name;
        scanf("%d:%d:%d:%d",&data[i].month,&data[i].day,&data[i].hour,&data[i].minute);
        string temp;
        cin>>temp;
        data[i].status = (temp=="on-line")?1:0; //快捷判断分支,用于转换字符串状态变量
        data[i].time =  data[i].day* 24 * 60+ data[i].hour*60 + data[i].minute;//time变量用于排序
    }
    //先按照姓名,再按照时间排序,怎么排?cmp函数里
    sort(data.begin(),data.end(),cmp);//排序规则
    //进行匹配,并把有效的筛选出来放在 custom中,建立name:node映射关系
    map<string ,vector<node>> custom;//建立一个映射函数(字典)
    for(int i=1;i<n;i++)
    {
        if(data[i].name==data[i-1].name && data[i].status==0 && data[i-1].status==1)//匹配规则
        {
            custom[data[i-1].name].push_back(data[i-1]);
            custom[data[i].name].push_back(data[i]);
        }
    }
    //下面计算 时间间隔和 费用 并进行输出
    for(auto it:custom){
        vector<node> temp = it.second; //vlaue 一个value有多个值,是个node数组
//
//        CYJJ 01
        cout << it.first;//key
        printf(" %02d\n", temp[0].month);
//      01:05:59 01:07:00 61 $12.10
        double total = 0.0;
        for(int i=1;i<temp.size();i+=2)
        {
            //计算 间隔和费用

            double t = billFromZero(temp[i], rate) - billFromZero(temp[i - 1], rate);
            printf("%02d:%02d:%02d %02d:%02d:%02d %d $%.2f\n", temp[i - 1].day, temp[i - 1].hour, temp[i - 1].minute, temp[i].day, temp[i].hour, temp[i].minute, temp[i].time - temp[i - 1].time, t);
            total+=t;
        }
        //        Total amount: $12.10
        printf("Total amount: $%.2f\n", total);
    }
    return 0;
}
 

3.1 更加简洁的思路

 

4. 收获

  • 复杂数据结构用结构体存储,若为数组,且需要排序,可以使用vector

  • 排序:先按姓名,再按时间 需要传入map函数,注意map函数的逻辑,这里错过

  • 筛选有效的数据:可以新建一个map字典,然后以关键字为key,以其它的部分为value,把满足条件的记录放进去

  • 计算加权时间:每一个小时都有不同的权重,最简单的办法是,计算一个记录从时间0 到time总共的花费,计算间隔花费只需要将两个记录的总花费相减即可

11. A1075

1. 题目描述

The ranklist of PAT is generated from the status list, which shows the scores of the submissions. This time you are supposed to generate the ranklist for PAT.

Input Specification:

Each input file contains one test case. For each case, the first line contains 3 positive integers, N (≤$10^4$), the total number of users, K (≤5), the total number of problems, and M (≤$10^5$), the total number of submissions. It is then assumed that the user id's are 5-digit numbers from 00001 to N, and the problem id's are from 1 to K. The next line contains K positive integers p[i] (i=1, ..., K), where p[i] corresponds to the full mark of the i-th problem. Then M lines follow, each gives the information of a submission in the following format:

user_id problem_id partial_score_obtained

where partial_score_obtained is either −1 if the submission cannot even pass the compiler, or is an integer in the range [0, p[problem_id]]. All the numbers in a line are separated by a space.

Output Specification:

For each test case, you are supposed to output the ranklist in the following format:

rank user_id total_score s[1] ... s[K]

where rank is calculated according to the total_score, and all the users with the same total_score obtain the same rank; and s[i] is the partial score obtained for the i-th problem. If a user has never submitted a solution for a problem, then "-" must be printed at the corresponding position. If a user has submitted several solutions to solve one problem, then the highest score will be counted.

The ranklist must be printed in non-decreasing order of the ranks. For those who have the same rank, users must be sorted in nonincreasing order according to the number of perfectly solved problems. And if there is still a tie, then they must be printed in increasing order of their id's. For those who has never submitted any solution that can pass the compiler, or has never submitted any solution, they must NOT be shown on the ranklist. It is guaranteed that at least one user can be shown on the ranklist.

Sample Input:

N K
7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0



00001 1 18
00001 2 18
00001 3 4
00001 4 2

00002 1 20
00002 2 12
00002 2 2
00002 2 25
00002 4 18

00004 3 25
00004 1 15
00004 2 0

00005 1 20
00005 1 19
00005 1 15
00005 3 22
00005 2 -1

00006 4 -1

00007 4 17
00007 2 25

Sample Output:

1 00002 63 20 25 - 18
2 00005 42 20 0 22 -          1
2 00007 42 - 25 - 17          1
2 00001 42 18 18 4 2          0
5 00004 40 15 0 25 -

2. 分析

  1. 建立数据结构,存储每一个人的答题信息

  1. 在读取信息的同时,更新每一题的分数,初始分数是-2,编译未通过为-1,其余均进行比较

  1. 信息录入完成后,设置一个总分变量,计算每一个人的总分

  1. 接下来进行筛选数据,将没有通过一题编译的去掉,没有进行提交过的也去掉

  1. 接下来按照规则进行输出

  1. 输出规则是 若总分一样,则排名一样,排名内部第一优先为 完美解决问题的个数,这个也需要设置一个变量记录,然后是ID递增,这是一个三个优先级的输出,使用一个cmp函数进行实现

  1. 之后直接输出即可

3 代码

 #include <iostream>
#include <algorithm>
#include "math.h"
#include "string.h"
#include "stdio.h"
#include <climits>
#include<map>
#include<vector>
#include <unordered_map>

using namespace std;


struct node{


    string ID;
    int s[6]={-2,-2,-2,-2,-2,-2};// 存储个人每一题对应的分数,-2表示未提交过,-1表示为通过编译,其它表示正常
    int total_socre = 0;// 总分存储
    int perproblem = 0;// 完美完成题目的数量
    int submit=0;

}; //信息结构体变量

typedef pair<string, node> PAIR;
typedef map<string ,node> Map;
bool cmp(PAIR a,PAIR b)
{

    if (a.second.total_socre != b.second.total_socre)
    {
        return a.second.total_socre > b.second.total_socre;
    }
    else if (a.second.perproblem!=b.second.perproblem)
    {
        return a.second.perproblem > b.second.perproblem;
    }
    else{
        return a.second.ID<b.second.ID;
    }
}
struct Cmp
{
    bool operator()(const Map a,const Map b)const
    {

    }
};
int main() {
    int N,K,M;
    scanf("%d %d %d",&N,&K,&M);
    int score[K];

    map<string ,node> data;//字典,索引为ID
    for(int i=0;i<K;i++)
    {
        scanf("%d",&score[i]);
    }
    int proindex=-1;
    int tempscore=-2;
    string tempID;
    node tempm,init;

    for(int i=0;i<M;i++)
    {

        cin>>tempID;
        scanf("%d",&proindex);
        scanf("%d",&tempscore);
        //这里无法直接初始化,只能是新的则加入,并初始化,旧的则直接修改之
        //如果是新用户
        if(data.find(tempID)==data.end())
        {
            data[tempID]=init;
            data[tempID].s[proindex]=tempscore;//不要忘记第一次也是有值的
            data[tempID].ID = tempID;
        }
        //如果是旧用户
        else
        {
            if(tempscore>data[tempID].s[proindex])
            {
                //存储进入node节点中
                data[tempID].s[proindex]=tempscore;
                data[tempID].ID = tempID;

            }
        }

    }
    //计算总分 并跟据总分进行筛选 总分为负值的可以不输出
    for (auto it:data){
        string tempID;
        tempID = it.first;
        for(int i=0;i<K;i++)
        {

            if(data[tempID].s[i+1]>=0)
            {
                data[tempID].submit=1;
                data[tempID].total_socre +=data[tempID].s[i+1];
            }

            if(it.second.s[i+1] ==score[i])
            {
                data[tempID].perproblem++;
            }
        }

    }
    //按照规则进行排序,首先将其转为vetor
    vector<PAIR> dataV(data.begin(),data.end());
    sort(dataV.begin(),dataV.end(),cmp);
    //输出
//    for(auto it:data)
//    {
//        cout<<it.first<<" ";
//        cout<<it.second.total_socre<<endl;
//    }
int index=1;
int rank=1;
int lastScore=-3;
    for(auto it:dataV)
    {

        if(it.second.total_socre>=0 && it.second.submit==1 )
        {
            if(index==1)
            {
                cout<<"1 ";
                index++;
            }
            else{
                if(it.second.total_socre<lastScore)
                {
                    cout<<index<<" ";
                    index++;
                    rank++;

                } else if(it.second.total_socre==lastScore)
                {
                    cout<<rank<<" ";
                    index++;
                }
            }

        cout<<it.first<<" ";
            lastScore=it.second.total_socre;
        cout<<it.second.total_socre<<" ";
        int tempScore;
        for(int i=0;i<K-1;i++)
        {
            tempScore=it.second.s[i+1];
            if(tempScore>-1)
            {
                cout<<tempScore<<" ";
            } else if(tempScore==-1){
                cout<<0<<" ";
            } else{
                cout<<"-"<<" ";
            }
        }

        tempScore=it.second.s[K];
        if(tempScore>-1)
        {
            cout<<tempScore<<endl;
        } else if(tempScore==-1){
            cout<<0<<endl;
        } else{
            cout<<"-"<<endl;
        }
    }
    }
    return 0;
}

3.1 更加简洁的思路

无需使用map,使用vetor

设置rank变量进入结构体当中,使得更有逻辑性,代码更加易读

 #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct node {
    int rank, id, total = 0;
    vector<int> score;
    int passnum = 0;
    bool isshown = false;
};
bool cmp1(node a, node b) {
    if(a.total != b.total)
        return a.total > b.total;
    else if(a.passnum != b.passnum)
        return a.passnum > b.passnum;
    else
        return a.id < b.id;
}

int main() {
    int n, k, m, id, num, score;
    scanf("%d %d %d", &n, &k, &m);
    vector<node> v(n + 1);
    for(int i = 1; i <= n; i++)
        v[i].score.resize(k + 1, -1);
    vector<int> full(k + 1);
    for(int i = 1; i <= k; i++)
        scanf("%d", &full[i]);
    for(int i = 0; i < m; i++) {
        scanf("%d %d %d", &id, &num, &score);
        v[id].id = id;
        v[id].score[num] = max(v[id].score[num], score);
        if(score != -1)
            v[id].isshown = true;
        else if(v[id].score[num] == -1)
            v[id].score[num] = -2;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= k; j++) {
            if(v[i].score[j] != -1 && v[i].score[j] != -2)
                v[i].total += v[i].score[j];
            if(v[i].score[j] == full[j])
                v[i].passnum++;
        }
    }
    sort(v.begin() + 1, v.end(), cmp1);
    for(int i = 1; i <= n; i++) {
        v[i].rank = i;
        if(i != 1 && v[i].total == v[i - 1].total)
            v[i].rank = v[i - 1].rank;
    }
    for(int i = 1; i <= n; i++) {
        if(v[i].isshown == true) {
            printf("%d %05d %d", v[i].rank, v[i].id, v[i].total);
            for(int j = 1; j <= k; j++) {
                if(v[i].score[j] != -1 && v[i].score[j] != -2)
                    printf(" %d", v[i].score[j]);
                else if(v[i].score[j] == -1)
                    printf(" -");
                else
                    printf(" 0");
            }
            printf("\n");
        }
    }
    return 0;
}

4. 收获

  1. 对于ID为00001,00002,且ID格式一样的,不包含字母的,且是顺序的,统统使用vetor

  1. 结构体的信息尽量完整,尽量包含每一个个体的全部独立信息

  1. rank排名的计算可以使用下面的程序

for(int i = 1; i <= n; i++) {
    v[i].rank = i;
    if(i != 1 && v[i].total == v[i - 1].total)
        v[i].rank = v[i - 1].rank;
}
  1. map 使用迭代器时,无法直接修改值,只能使用 data[index]的方式修改

  1. 将map转为 vetor时,可以使用typedef pair<string, node> PAIR;当然这个也可以用于无序的,key可以重复的字典中

  1. map的cmp函数没有成功,尽量不用

  1. 关于结构体的比较的写法

传入的参数格式,一定是vetor元素的格式

优先级高的比较写在前面

bool cmp(PAIR a,PAIR b)

{

if (a.second.total_socre != b.second.total_socre)

{

return a.second.total_socre > b.second.total_socre;

}

else if (a.second.perproblem!=b.second.perproblem)

{

return a.second.perproblem > b.second.perproblem;

}

else{

return a.second.ID<b.second.ID;

}

}

12. A1095 Cars on Campus 30

1. 题目描述

Zhejiang University has 8 campuses and a lot of gates. From each gate we can collect the in/out times and the plate numbers of the cars crossing the gate. Now with all the information available, you are supposed to tell, at any specific time point, the number of cars parking on campus, and at the end of the day find the cars that have parked for the longest time period.

Input Specification:

Each input file contains one test case. Each case starts with two positive integers N (≤104), the number of records, and K (≤8×104) the number of queries. Then N lines follow, each gives a record in the format:

plate_number hh:mm:ss status

where plate_number is a string of 7 English capital letters or 1-digit numbers; hh:mm:ss represents the time point in a day by hour:minute:second, with the earliest time being 00:00:00 and the latest 23:59:59; and status is either in or out.

Note that all times will be within a single day. Each in record is paired with the chronologically next record for the same car provided it is an out record. Any in records that are not paired with an out record are ignored, as are out records not paired with an in record. It is guaranteed that at least one car is well paired in the input, and no car is both in and out at the same moment. Times are recorded using a 24-hour clock.

Then K lines of queries follow, each gives a time point in the format hh:mm:ss. Note: the queries are given in ascending order of the times.

Output Specification:

For each query, output in a line the total number of cars parking on campus. The last line of output is supposed to give the plate number of the car that has parked for the longest time period, and the corresponding time length. If such a car is not unique, then output all of their plate numbers in a line in alphabetical order, separated by a space.

Sample Input:

16 7
JH007BD 18:00:01 in
ZD00001 11:30:08 out
DB8888A 13:00:00 out
ZA3Q625 23:59:50 out
ZA133CH 10:23:00 in
ZD00001 04:09:59 in
JH007BD 05:09:59 in
ZA3Q625 11:42:01 out
JH007BD 05:10:33 in
ZA3Q625 06:30:50 in
JH007BD 12:23:42 out
ZA3Q625 23:55:00 in
JH007BD 12:24:23 out
ZA133CH 17:11:22 out
JH007BD 18:07:01 out
DB8888A 06:30:50 in
05:10:00
06:30:50
11:00:00
12:23:42
14:00:00
18:00:00
23:59:00







JH007BD 05:09:59 in

JH007BD 05:10:33 in
JH007BD 12:23:42 out

JH007BD 12:24:23 out

JH007BD 18:00:01 in
JH007BD 18:07:01 out



05:10:00
06:30:50
11:00:00
12:23:42
14:00:00
18:00:00
23:59:00

Sample Output:

1
4
5
2
1
0
1
JH007BD ZD00001 07:20:09

2. 分析

  1. 一个结构体:ID,time in or out,int lenth

  1. 一个vetor存储这个结构体,然后先对ID进行排序,再对time进行排序

  1. 然后对其进行筛选,要求相同ID的出入信息配对

  1. 查询:

  1. 对每一个ID的出入时间进行比较,如果 进入时间 小于 查询时间 且 出去时间 大于 查询时间 那么 park++;

  1. 计算最长length,并输出其ID 还有 length

3 代码

超时!

 #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;


struct Qtime{
    int h,m,s;
    int time;
};
struct node{
    string ID;
    int h,m,s;
    bool status;
    int len=-1;
    int time;
};
bool cmp(node a,node b)
{
    if(a.ID!=b.ID)
    {
        return a.ID<b.ID;
    } else
    {
        return a.time<b.time;
    }
}

int Query(Qtime qtime, map<string ,vector<node>> dataM)
{
    int park=0;
    int queryTime = qtime.time;
    for(auto it:dataM)
    {
        vector<node> temp = it.second;
        for(int i=0;i<temp.size()-1;i+=2)
        {
            if(queryTime>=temp[i].time && temp[i+1].time> queryTime)
            {
                park++;
            }
        }
    }
    return park;
}
int main()
{
    int K,queries;
    scanf("%d %d",&K,&queries);
    vector<node> data(K);
    for(int i=0;i<K;i++)
    {
        cin>>data[i].ID;
        scanf("%d:%d:%d",&data[i].h,&data[i].m,&data[i].s);
        //计算从0 开始的time
        data[i].time = data[i].h*60 * 60+ data[i].m * 60 + data[i].s;
        string temp;
        cin>>temp;
        data[i].status = (temp=="in")? true: false;
    }
    vector<Qtime>QTime(queries);
    for(int i=0;i<queries;i++)
    {
        scanf("%d:%d:%d",&QTime[i].h,&QTime[i].m,&QTime[i].s);
        QTime[i].time = QTime[i].h*60 * 60+ QTime[i].m * 60 + QTime[i].s;
    }


//    对data 进行排序
    sort(data.begin(),data.end(),cmp);
    map<string ,vector<node>> dataM;
    // 进行筛选
    map<string ,int> parkLength;
    int Maxtime=-1;
    map<string ,int> query;
    for(int i=1;i<K;i++ )
    {
//        parkLength[data[i].ID] = 0;
        if(data[i].ID==data[i-1].ID && data[i].status== false & data[i-1].status== true)
        {

            dataM[data[i].ID].push_back(data[i-1]);
            dataM[data[i].ID].push_back(data[i]); // value是一个vetor,可以使用puch_back 加入元素
            parkLength[data[i].ID] += data[i].time-data[i-1].time; //一块计算 总时间

        }
        //一块计算最大停车时长
        Maxtime = max(Maxtime, parkLength[data[i].ID]);
    }

//    for (auto it :dataM)
//    {
//        cout<<it.first<<" ";
//        for(int i=0;i<it.second.size();i++)
//        {
//            cout<<it.second[i].time<<" ";
//        }
//        cout<<endl;
//    }
//    进行查询
    for(int i=0;i<queries;i++)
    {
        int park=0;
        park = Query(QTime[i], dataM);
        cout<< park<<endl;
    }
//优化查询,由于查询的时间是递增的,因此在查询后面的过程中,是不需要再所以前面的了
    /*
     * 车辆进入 flag=1,车辆出去,flag =-1
     * 在query[0] 时间点上,计算车辆数量 cnt[0]
     * 在query[1] 时间点上,车辆数量 = cnt[0] +
     * */
    //计算 停留最长时间的


//    for (auto it :dataM)
//    {
//        int total_time=0;
//
//        for(int i=0;i<it.second.size();i+=2)
//        {
//
//            total_time+= it.second[i].len;
//        }
//        parkLength[it.first] = total_time;
//    }


    string MaxID[parkLength.size()];
    int n=0;
    for(auto it:parkLength)
    {

        if(it.second==Maxtime)
        {
            MaxID[n++] = it.first;
        }
    }

    for(int i=0;i<n;i++)
    {
        cout<<MaxID[i]<<" ";
    }
    int hh,mm,ss;
    hh = Maxtime/3600;
    mm = (Maxtime%3600)/60;
    ss = (Maxtime%60);
    printf("%02d:%02d:%02d\n",hh,mm,ss);

    return 0;
}

3.1 更加简洁的思路

 

4. 收获

  1. 喵的

  1. 超时

  1. 主要原因在于 查询没有进行优化

  1. 不知道怎么优化,挺难的

  1. 一个思想:尽量集中化处理,不要分散,能在一个循环内的,就尽量在一个循环内

14. A1070

1. 题目描述

Mooncake is a Chinese bakery product traditionally eaten during the Mid-Autumn Festival. Many types of fillings and crusts can be found in traditional mooncakes according to the region's culture. Now given the inventory amounts and the prices of all kinds of the mooncakes, together with the maximum total demand of the market, you are supposed to tell the maximum profit that can be made.

Note: partial inventory storage can be taken. The sample shows the following situation: given three kinds of mooncakes with inventory amounts being 180, 150, and 100 thousand tons, and the prices being 7.5, 7.2, and 4.5 billion yuans. If the market demand can be at most 200 thousand tons, the best we can do is to sell 150 thousand tons of the second kind of mooncake, and 50 thousand tons of the third kind. Hence the total profit is 7.2 + 4.5/2 = 9.45 (billion yuans).

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (≤1000), the number of different kinds of mooncakes, and D (≤500 thousand tons), the maximum total demand of the market. Then the second line gives the positive inventory amounts (in thousand tons), and the third line gives the positive prices (in billion yuans) of N kinds of mooncakes. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the maximum profit (in billion yuans) in one line, accurate up to 2 decimal places.

Sample Input:

3 200
180 150 100
7.5 7.2 4.5

24  20.8 22

Sample Output:

9.45

2. 分析

  1. 计算单价,由高到底排序

  1. 优先卖单价高的货物

3 代码

 #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
using namespace std;
struct mooncake{
    double left;
    double price;
    double pl;
};
bool cmp( mooncake a,mooncake b)
{

    return a.pl>b.pl;
}
int main()
{

    int k,maxDemand;
    scanf("%d %d",&k,&maxDemand);
    vector<mooncake> data(k);
    for(int i=0;i<k;i++)
    {
        scanf("%lf",&data[i].left);
    }
    for(int i=0;i<k;i++)
    {
        scanf("%lf",&data[i].price);
        data[i].pl = data[i].price / data[i].left;
    }
    sort(data.begin(),data.end(),cmp);

    double profit=0;
    for(int i=0;i<k;i++)
    {
        if(maxDemand>=data[i].left)
        {
            maxDemand-= data[i].left;
            profit+= data[i].price;
        } else{
            data[i].left -= maxDemand;

            profit+= maxDemand* data[i].pl;
            break;
        }

    }
    printf("%.2f",profit);
    return 0;

}

3.1 更加简洁的思路

 

4. 收获

  1. for 循环的终止条件,尽量通过i<K 和 break 来控制

  1. 除法 是直接保留小数的,最后关于输出精度,取决于printf

15. A1067

1. 题目描述

Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (≤105) followed by a permutation sequence of {0, 1, ..., N−1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10
3 5 7 2 6 4 9 0 8 1

5 
4 0 2 1 3

Sample Output:

9

2. 分析

  1. 将 0 所在的位置 ,将其主人请回家,然后 0 到这个位置

  1. 如果 0 回到原位了,那么?

  1. 与一个不在本位的数字相换

  1. 可以利用k递增来减少比较次数,因为k以前的位置一定已经被替换过了,k以后的位置开始寻找即可

  1. 终止条件是什么?

  1. 没有不在本位的数字了 使用left变量来控制

3 代码

 #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
using namespace std;
bool cmp(int a,int b)
{
    return a<b;
}

int main()
{
    int N;

    scanf("%d",&N);
    int left=N-1;//非0的数字不在本位的个数
    int pos[100010];
    int t;
    int cnt=0;
    for(int i=0;i<N;i++)
    {
        cin>>t;
        pos[t] = i;//记录下来每个数字所在的位置
        if(t==i && t!=0)
        {
            left--;
        }
    }
    int k=1;
    while(left>0)
    {
        if(pos[0] == 0)
        {
//            找一个不在本位上数字与0交换
        while(k<N)
        {
          if(pos[k]!=k) //直接从k开始判断 k是递加的,因为k以前的已经被换过了,不需要在看了
          {
              swap(pos[0],pos[k]);
              cnt++;
              break;
          }
           k++;
        }

        }
        while(pos[0] != 0)
        {
            swap(pos[0], pos[pos[0]]);
            cnt++;
            left--;
        }
    }
    cout << cnt<<endl;
    return 0;
}


3.1 更加简洁的思路

 

4. 收获

  1. 数据必须模拟完整,排除中间的一些情况

  1. 如果出现样例可以通过,但是OJ不通过,不要着急,一定有错,慢慢改

  1. 使用k++递增办法,来减少比较次数(类似与冒泡排序法的第二层循环改进)

13. A1048

1. 题目描述

Eva loves to collect coins from all over the universe, including some other planets like Mars. One day she visited a universal shopping mall which could accept all kinds of coins as payments. However, there was a special requirement of the payment: for each bill, she could only use exactly two coins to pay the exact amount. Since she has as many as 105 coins with her, she definitely needs your help. You are supposed to tell her, for any given amount of money, whether or not she can find two coins to pay for it.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive numbers: N (≤105, the total number of coins) and M (≤103, the amount of money Eva has to pay). The second line contains N face values of the coins, which are all positive numbers no more than 500. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the two face values V1 and V2 (separated by a space) such that V1+V2=M and V1≤V2. If such a solution is not unique, output the one with the smallest V1. If there is no solution, output No Solution instead.

Sample Input 1:

8 15
1 2 8 7 2 4 11 15

Sample Output 1:

4 11

Sample Input 2:

7 14
1 8 7 2 4 11 15

Sample Output 2:

No Solution

2. 分析

  1. 找到正好2 个硬币 = 总价 即可

  1. 注意超时

  1. 对数组进行标记 1 2(2) 4 7 8 11 15

  1. 对数组进行遍历 (i,money-i)看看有没有满足条件的

3 代码

two points算法 适用于 没有限制大小的硬币面额

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
using namespace std;
bool cmp(int a,int b)
{
    return a<b;
}

int main() {
    int k, moeny;
    scanf("%d %d",&k,&moeny);
//    标记数组

    int a[100001]={0};
    int coin;
    int coin1=0,coin2=0;
    for(int i=0;i<k;i++)
    {
        scanf("%d",&coin);
        a[i] = coin;
    }
    sort(a,a+k);
    for(int i=0,j=k-1;i<k,i<j;)
    {
        if(a[i]!=0&&a[j]!=0&&i<j)
        {
            if(a[i]+a[j]==moeny)
            {
                coin1 = a[i];
                coin2 = a[j];
                break;
            }
            if(a[i]+a[j]<moeny)
            {
                i++;
            }
            if(a[i]+a[j]>moeny)
            {
                j--;
            }
        } else{
          if(a[i]==0) i++;
          if(a[j]==0) j++;
        }

    }

    if(coin1&&coin2)
    {
        cout<<coin1<<" "<<coin2<<endl;
    } else{
        cout<<"No Solution"<<endl;
    }

    return 0;
}


3.1 更加简洁的思路

hash数组

  #include <iostream>
using namespace std;
int a[1001];
int main() {
    int n, m, temp;
    scanf("%d %d", &n, &m);
    for(int i = 0; i < n; i++) {
        scanf("%d", &temp);
        a[temp]++;
    }
    for(int i = 0; i < 1001; i++) {
        if(a[i]) {
            a[i]--;
            if(m > i && a[m-i]) {
                printf("%d %d", i, m - i);
                return 0;
            }
            a[i]++;
        }
    }
    printf("No Solution");
    return 0;
}

4. 收获

  1. two points 问题 (双指针解决(适用于大小无限制的),hash数组解决)

  1. 由于硬币数值小于500,因此使用hash数组,通过i,可以迅速找到money-i,判断两个是否存在即可

17. A1089 Insert or Merge

1. 题目描述

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Merge sort works as follows: Divide the unsorted list into N sublists, each containing 1 element (a list of 1 element is considered sorted). Then repeatedly merge two adjacent sublists to produce new sorted sublists until there is only 1 sublist remaining.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤100). Then in the next line, N integers are given as the initial sequence. The last line contains the partially sorted sequence of the N numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in the first line either "Insertion Sort" or "Merge Sort" to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resuling sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

Sample Input 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

Sample Output 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

2. 分析

  1. 需要模拟插入排序 与归并排序

  1. 然后在每一个iter去判断 属于哪个排序算法

3 代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
using namespace std;

int main()
{
    int N;
    scanf("%d",&N);
    int IS[N],MS[N];
    int res[N];
    int num;
    for(int i=0; i < N; i++)
    {
        scanf("%d",&num);
        IS[i] = num;
        MS[i] = num;
    }
    for(int i=0; i < N; i++)
    {
        scanf("%d",&num);
        res[i] = num;

    }
    int i,j=0;
    for(i=0;i<N-1&&res[i]<=res[i+1];i++);
    for(j=i+1;j<N && IS[j]==res[j];j++);// j=9 后,进行一次循环,在令j++

    if(j==N)
    {
        cout<<"Insertion Sort"<<endl;
        sort(IS,IS+i+2);//i从 0开始的,因此 需要多加一个1  才能表示 要排序的个数
        for(int i=0;i<N-1;i++)
        {
            cout<<IS[i]<<" ";
        }
        cout<<IS[N-1];
    } else {
        cout << "Merge Sort" << endl;
        int k = 1, flag = 1;
        while (flag) {
            flag = 0;
            for (i = 0; i < N; i++) {
                if (MS[i] != res[i])
                    flag = 1;//说明还没到归并应该到的步骤,需要继续进行归并
            }
            k = k * 2;// 归并段的长度每次都乘2
            for (i = 0; i < N / k; i++)//分段进行排序
                sort(MS + i * k, MS + (i + 1) * k);

            sort(MS + N / k * k, MS + N);//剩余的零碎段进行排序

        }
        for (int i = 0; i < N - 1; i++) {
            cout << MS[i] << " ";
        }
        cout << MS[N - 1] ;
    }
    return 0;
}

3.1 更加简洁的思路

 

4. 收获

  1. 大部分情况不会让你手写两个排序算法的

  1. 但是排序算法必须熟悉,递归与非递归的,都要能够写出来

  1. for循环中,满足条件后,i还会再加一 ,返回的应该是不满足条件的时候i的值

18. A1101

1. 题目描述

There is a classical process named partition in the famous quick sort algorithm. In this process we typically choose one element as the pivot. Then the elements less than the pivot are moved to its left and those larger than the pivot to its right. Given N distinct positive integers after a run of partition, could you tell how many elements could be the selected pivot for this partition?

For example, given N=5 and the numbers 1, 3, 2, 4, and 5. We have:

  • 1 could be the pivot since there is no element to its left and all the elements to its right are larger than it;

  • 3 must not be the pivot since although all the elements to its left are smaller, the number 2 to its right is less than it as well;

  • 2 must not be the pivot since although all the elements to its right are larger, the number 3 to its left is larger than it as well;

  • and for the similar reason, 4 and 5 could also be the pivot.

Hence in total there are 3 pivot candidates.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤$10^5$). Then the next line contains N distinct positive integers no larger than $10^9$. The numbers in a line are separated by spaces.

Output Specification:

For each test case, output in the first line the number of pivot candidates. Then in the next line print these candidates in increasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the end of each line.

Sample Input:

5
1 3 2 4 5

Sample Output:

3
1 4 5

2. 分析

  1. 作为pivot的条件是

  1. 左边的比它都小,右边的比他都大

  1. 如何快速判断这个条件呢?

  1. 思路借鉴

  1. 利用大小继承思路,建立两个数组,LeftMax RightMin 然后循环列表一遍赋值

  1. 再通过列表与数组 来确定是不是pivot

3 代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>

using namespace std;
const int MAXN = 100010;
const int INF = 0x3fffffff;
int a[MAXN];
int b[MAXN];
int leftMax[MAXN],rightMin[MAXN];
int main() {
    int N;
    scanf("%d",&N);

    for(int i=0;i<N;i++)
    {
        scanf("%d",&a[i]);
    }

    leftMax[0]= INT16_MIN;//记录左侧的最大值  leftMax[i]表示 a[i]左侧的最大值
    rightMin[N-1] = INF;//rightMin[i] 表示 a[i]右侧的最小值 也就是 a[i+1]---a[N-1]的最小值
//                    注意 ,INFINITY为无限大
    for(int i=1;i<N;i++)
    {
          //做的是取最大的,直接用max函数就可以
        leftMax[i] = max(leftMax[i-1],a[i-1]);
    }
    for(int i=N-1-1;i>=0;i--)
    {
        rightMin[i] = min(rightMin[i+1],a[i+1]);
    }
    int index=0;
    for(int i=0;i<N;i++)
    {
        if(a[i]>leftMax[i]&&a[i]<rightMin[i])
        {
            b[index++] = a[i];
        }
    }


    cout<<index<<endl;
    if(index>0)
    {
        for(int i=0;i<index-1;i++)
        {
            cout<<b[i]<<" ";
        }
        cout<<b[index-1]<<endl;
    } else
        cout<<endl;


    return 0;
} 

3.1 更加简洁的思路

 

4. 收获

  1. 此题的数字大小继承思路非常值得研究,方便用于判断左侧最大,与右侧最下

  1. 尽量用max,min函数来表示最大最小的提取

  1. 注意最大值:const int INF = 0x3fffffff;

19. A1069 The Black Hole of Numbers

1. 题目描述

For any 4-digit integer except the ones with all the digits being the same, if we sort the digits in non-increasing order first, and then in non-decreasing order, a new number can be obtained by taking the second number from the first one. Repeat in this manner we will soon end up at the number 6174 -- the black hole of 4-digit numbers. This number is named Kaprekar Constant.

For example, start from 6767, we'll get:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
... ...

Given any 4-digit number, you are supposed to illustrate the way it gets into the black hole.

Input Specification:

Each input file contains one test case which gives a positive integer N in the range (0,$10^4$).

Output Specification:

If all the 4 digits of N are the same, print in one line the equation N - N = 0000. Else print each step of calculation in a line until 6174 comes out as the difference. All the numbers must be printed as 4-digit numbers.

Sample Input 1:

6767

Sample Output 1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174

Sample Input 2:

2222

Sample Output 2:

2222 - 2222 = 0000

2. 分析

  1. 非增排序 - 非减排序

  1. 排序即可

  1. 用字符串排序就行

3 代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>

using namespace std;
bool cmp(char c1,char c2)
{
//又写错了!!!!

        return c1>c2;

}
int k=0;
void Solve(string num)
{
    num.insert(0,4-num.length(),'0'); //需要进行补全,不要忘记
    if(num=="6174"&&k!=0)
    {

        return;
    } else
    {

    k++;
    vector<char> num1(4);
    vector<char> num2(4);
    for(int i=0;i<4;i++)
    {
        num1[i] = num[i];
        num2[i] = num[i];
    }
    sort(num2.begin(),num2.end());
    sort(num1.begin(),num1.end(),cmp);
    string num3,num4;
    for(int i=0;i<4;i++)
    {
        num3+=num1[i];
        num4+=num2[i];
    }
    string num5 = to_string(stoi(num3) - stoi(num4));
    num5.insert(0,4-num5.length(),'0');


        if(num5!="0000")
        {
            cout<<num3<<" - "<<num4<<" = "<<num5<<endl;
            Solve(num5);
        }
        else{
            cout<<"0000"<<endl;
            return;
        }


    }
}

int main() {

    string num;
    cin>>num;
    num.insert(0,4-num.length(),'0');
    do{
        string a=num,b =num;
        sort(a.begin(),a.end(),cmp);
        sort(b.begin(),b.end());
        string c = to_string(stoi(a)- stoi(b)) ;
        c.insert(0,4-c.length(),'0');
        cout<<a<<" - "<<b<<" = "<<c<<endl;
        num = c;
    } while (num!="6174" && num != "0000");

//    Solve(num);
    return 0;
} 

3.1 更加简洁的思路

 

4. 收获

  1. 字符串转数字 stoi,stof

  1. 一定一定注意数字与字符串的区别,数字是会省略0 的要insert

  1. 一定一定注意特殊情况下的考虑,边界情况

20. A1104 Sum of Number Segments

1. 题目描述

Given a sequence of positive numbers, a segment is defined to be a consecutive subsequence. For example, given the sequence { 0.1, 0.2, 0.3, 0.4 }, we have 10 segments: (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) and (0.4).

Now given a sequence, you are supposed to find the sum of all the numbers in all the segments. For the previous example, the sum of all the 10 segments is 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N, the size of the sequence which is no more than 105. The next line contains N positive numbers in the sequence, each no more than 1.0, separated by a space.

Output Specification:

For each test case, print in one line the sum of all the numbers in all the segments, accurate up to 2 decimal places.

Sample Input:

4
0.1 0.2 0.3 0.4

Sample Output:

5.00

2. 分析

  1. 求出序列

  1. 找规律来

  1. 第一个数出现N次

  1. 第二个数出现N-1次+第一个数-1次 = 2(N-1)

  1. 第三个数出现N-2次 + 第一个数-1次+第二个数-1次

  1. 有没有什么直接的规律呢?

  1. 算一算,有规律的

  1. 别着急,慢慢来,肯定可以找出来的

  1. 第i个 (i+1)(N-i)

3 代码

 
#include <iostream>
using namespace std;
int main() {
    int n;
    cin >> n;
    long long sum = 0;
    double temp;
    for (int i = 1; i <= n; i++) {
        cin >> temp;
        sum += (long long) (temp * 1000) * i * (n - i + 1);
    }
    printf("%.2f", sum / 1000.0);
    return 0;
}

3.1 更加简洁的思路

 

4. 收获

  1. 此题首先要找规律 不要着急,慢慢来

  1. 然后是精度问题:尽量转为整型存储,这样不会损失精度 但是 double会损失精度的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值