hope实验室预备役第一次测试题解和总结。

前言

由于最近忙着在学习数据结构(被弄昏头了),而忘记了将预备役第一次测试的题解和总结记录下来,直到今天有进行了第二次测试。我想,对于每一次测试,都是有意义将其整理下来,并进行反思。

一.A - Rook.

你可能知道,国际象棋是一种在一个排列成8x8网格的棋盘上进行的游戏。这个棋盘的列用从a到h的字母标记,行用从1到8的数字标记。每个方格由它所属的行和列来描述。

车是国际象棋中的一个棋子。在它的回合中,它可以水平或垂直地移动任意非零数量的方格。你的任务是找出车在空棋盘上所有可能的移动方式。

输入

输入的第一行包含一个整数t(1≤t≤64)— 测试用例的数量。接下来是每个测试用例的描述。

每个测试用例包含一个由两个字符组成的字符串,描述了车所在的方格。第一个字符是从a到h的字母,表示列的标记,第二个字符是从1到8的数字,表示行的标记。

相同的位置可能出现在多个测试用例中。

输出

对于每个测试用例,以与输入相同的格式输出车可以移动到的所有方格的描述。

你可以以任何顺序输出每个测试用例中的方格。

示例 1

InputcopyOutputcopy
1
d5
d1
d2
b5
g5
h5
d3
e5
f5
d8
a5
d6
d7
c5
d4

 

第一题没什么好说的,就根据题目意思来就行,就是输出一个点(x,y)所在的排和列(不包括该点)。

#include<stdio.h>
int main()
{
    int n;
    char a[100];         //将他们都当做字符录入
    scanf("%d",&n);
    while(n--)
    {
        scanf(" %c%c",&a[0],&a[1]);    //a[0]控制列,a[1]控制行。
        for(int i=1;i<=8;i++)
        {
            if(i==a[1]-48)             //该列中除去自己本身的点
                continue;
            else
            printf("%c%d\n",a[0],i);
        }
        for(int i=97;i<=104;i++)       //通过ascll值来实现从a到h的输入
        {
            if(i==a[0])                //在该行中除去自己本身的点
                continue;
            else
            printf("%c%c\n",i,a[1]);
        }
    }
    return 0;
}

二.B - Satisfying Constraints.

Alex正在解决一个问题。他对整数 k 有 n 个约束条件。约束条件有三种类型:

  1. k 必须 大于或等于 某个整数 x;
  2. k 必须 小于或等于 某个整数 x;
  3. k 必须 不等于 某个整数 x。

帮助Alex找出满足所有 n 约束条件的整数 k 的数量。保证答案是有限的(至少存在一种 11 类型的约束条件和至少一种 22 类型的约束条件)。同时,保证 没有两个约束条件完全相同。

输入

每个测试包含多个测试用例。第一行包含一个整数 t (1≤t≤500) —— 测试用例的数量。接下来是测试用例的描述。

每个测试用例的第一行包含一个整数 n (2≤n≤100) —— 约束条件的数量。

接下来的 n行描述了约束条件。每行包含两个整数 a 和 x (a∈{1,2,3},1≤x≤109)。 a 表示约束条件的类型。如果是 a=1,则 k必须大于或等于 x。如果是 a=2,则 k 必须小于或等于 x。如果是 a=3,则 k 必须不等于 x。

保证存在有限数量的整数满足所有 n约束条件(至少存在一种 11类型的约束条件和至少一种 2 类型的约束条件)。同时,保证没有两个约束条件完全相同(换句话说,所有的 (a,x) 对都是不同的)。

输出

对于每个测试用例,输出一个整数 —— 满足所有 n约束条件的整数 k的数量。

示例 1

InputcopyOutputcopy
6
4
1 3
2 10
3 1
3 5
2
1 5
2 4
10
3 6
3 7
1 2
1 7
3 100
3 44
2 100
2 98
1 3
3 99
6
1 5
2 10
1 9
2 2
3 2
3 9
5
1 1
2 2
3 1
3 2
3 3
6
1 10000
2 900000000
3 500000000
1 100000000
3 10000
3 900000001
7
0
90
0
0
800000000

注意

在第一个测试用例中,k≥3 且 k≤10。此外,k≠1 且 k≠5。满足约束条件的可能整数 k 是 3,4,6,7,8,9,10。因此答案是 7。

在第二个测试用例中,k≥5 且 k≤4,这是不可能的。因此答案是 0。

本题也是根据题目意思就可以解决了,重点就是这三句话:

  1. k 必须 大于或等于 某个整数 x;
  2. k 必须 小于或等于 某个整数 x;
  3. k 必须 不等于 某个整数 x。

 就是先通过1和2的条件确定范围,将1的最终值设为r,2的最终值设为l,总和为l-r+1。(注意r要取最大,l要取最小),最后判断3的条件在不在范围中,在就总和将一,最后输出总和就ok了

#include<stdio.h>
int max(int x,int y)
{
    return x>y?x:y;
}
int min(int x,int y)
{
    return x>y?y:x;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        long long n,r=0,l=10000000000,sum=0;         //l尽量大,sum尽量小。
        long long a[1000],b[1000],c[1000]={0};
        scanf("%lld",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%lld%lld",&a[i],&b[i]);
            if(a[i]==1)
                r=max(b[i],r);             //更新区间左端点的值(最大)
            if(a[i]==2)
                l=min(b[i],l);             //更新区间右端点的值(最小)
            if(a[i]==3)
                c[i]=b[i];
        }
        if(r<=l)
            sum=l-r+1;                     //区间内满足条件的点的总和
        else
            sum=0;
        for(int i=0;i<n;i++)
        {
            if(c[i]>=r&&c[i]<=l)           //3条件不满足条件的点,找到sum--
                sum--;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

 

三.C - Sending Messages.

斯特潘是一个非常忙碌的人。今天他需要在时刻m1,m2,…mn(mi<mi+1)发送n条消息。不幸的是,在时刻0,他的手机只剩下f单位的电量。在时刻0,手机已经打开。

手机每工作单位时间会消耗a单位的电量。此外,斯特潘可以随时关闭手机,稍后再打开。每次这样做会消耗b单位的能量。考虑到开关机是瞬间完成的,所以你可以在时刻x打开手机并发送消息,反之亦然,在时刻x发送消息并关闭手机。

如果在任何时刻电量降到0(变成≤0),就无法在那时刻发送消息。

由于所有消息对斯特潘来说都非常重要,他想知道是否能在不充电的情况下发送所有消息。

输入

输入的第一行包含一个整数t(1≤t≤104)— 测试用例的数量。接下来是每个测试用例的描述。

每个测试用例的第一行包含四个整数n、f、a和b(1≤n≤2⋅105、1≤f,a,b≤109)— 消息数量、初始手机电量、单位时间电量消耗和连续开关机消耗。

每个测试用例的第二行包含n个整数m1,m2,…,mn(1≤mi≤109、mi<mi+1)— 需要发送消息的时刻。

保证在一个测试中n的总和不超过2⋅105

输出

对于每个测试用例,如果斯特潘能发送所有消息,则输出“YES”,否则输出“NO”。

你可以以任何大小写形式输出每个字母(大写或小写)。例如,字符串“yEs”、“yes”、“Yes”和“YES”都会被接受为肯定答案。

示例 1

InputcopyOutputcopy
6
1 3 1 5
3
7 21 1 3
4 6 10 13 17 20 26
5 10 1 2
1 2 3 4 5
1 1000000000 1000000000 1000000000
1000000000
3 11 9 6
6 8 10
12 621526648 2585904 3566299
51789 61859 71998 73401 247675 298086 606959 663464 735972 806043 806459 919683
NO
YES
YES
NO
NO
YES

注意

在示例的第一个测试用例中,在时刻00,手机电量为33。在不关闭的情况下,在时刻33发送消息将消耗(3−0)⋅1=3(3−0)⋅1=3单位的电量。在这种情况下,电量将降到00,斯特潘将无法发送消息。而连续开关机会导致手机电量减少55,因此这种方式也不可行。

在示例的第三个测试用例中,在时刻00,手机电量为1010。手机每单位时间会消耗11单位的电量,而连续开关机会消耗22单位的电量。为了发送所有消息,可以采取以下行动:

  • 在时刻00关闭手机,时刻11打开,此时剩余10−2=810−2=8单位电量;
  • 在时刻11发送消息;
  • 在时刻22发送消息,此时剩余8−(2−1)⋅1=78−(2−1)⋅1=7单位电量;
  • 在时刻22关闭手机,时刻33打开,此时剩余7−2=57−2=5单位电量;
  • 在时刻33发送消息;
  • 在时刻33关闭手机,时刻44打开,此时剩余5−2=35−2=3单位电量;
  • 在时刻44发送消息;
  • 在时刻44关闭手机,时刻55打开,此时剩余3−2=13−2=1单位电量;
  • 在时刻55发送消息。

在示例的最后一个(第六个)测试集中,如果你的解决方案中存在整数溢出,可能会失败。

 

刚开始拿到这到题的时候可能感觉有的绕人,不好理解,找不到思路。其实多读几遍以后会发现,这道题其实很简单。就是如果关机消耗的电量如果比不关机等待消耗的电量(就是相邻两项之差乘上每秒耗电量)小,就关机,在总电量上减去关机消耗的电量,反之。最后看剩余电量是否大于0。

 

#include<stdio.h>
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        long long n,f,a,b,sum=0;
        long long k[200001]={0};
        scanf("%lld%lld%lld%lld",&n,&f,&a,&b);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&k[i]);
        }
        for(int i=1;i<=n;i++)
        {
            if((k[i]-k[i-1])*a>b)          //如果关机更省点,就加上关机的耗电量。
                sum+=b;
            else
                sum+=(k[i]-k[i-1])*a;      //反之,加上不关机等待的耗电量。
        }
        if(sum>=f)                         //如果耗电量比剩余电量大就不行
            printf("NO\n");
        else
            printf("YES\n");               //反之就行。
    }
    return 0;
}

 

四.D - Infinite Replacement.

给一个只含小写字母 a 的字符串 s和一个用来替换的字符串 t 。

你可以将 s 中任意一个字母 a 用 t来替换,替换的次数不限。

对于每一个 s和 t ,你可以得到几个不同的字符串?如果有无限个,输出 -1 。

You are given a string s, consisting only of Latin letters 'a', and a string t, consisting of lowercase Latin letters.

In one move, you can replace any letter 'a' in the string s with a string t. Note that after the replacement string s might contain letters other than 'a'.

You can perform an arbitrary number of moves (including zero). How many different strings can you obtain? Print the number, or report that it is infinitely large.

Two strings are considered different if they have different length, or they differ at some index.

Input

输入的第一行包含一个整数 q(1≤q≤104),表示测试数据组数。

对于每组测试数据:

  • 第一行包含一个只包含 a 的非空字符串 s,s 的长度不超过 50。
  • 第二行包含一个非空小写英文字符串 t,t 的长度不超过 5050。

The first line contains a single integer q(1≤q≤104) — the number of testcases.

The first line of each testcase contains a non-empty string s, consisting only of Latin letters 'a'. The length of s doesn't exceed 5050.

The second line contains a non-empty string t, consisting of lowercase Latin letters. The length of t doesn't exceed 5050.

Output

对于每组测试数据,输出一个整数,表示你可以得到的不同的字符串数量。如果有无限个不同字符串,输出 -1

For each testcase, print the number of different strings s that can be obtained after an arbitrary amount of moves (including zero). If the number is infinitely large, print -1. Otherwise, print the number.

Sample 1

InputcopyOutputcopy
3
aaaa
a
aa
abc
a
b
1
-1
2

Note

In the first example, you can replace any letter 'a' with the string "a", but that won't change the string. So no matter how many moves you make, you can't obtain a string other than the initial one.

In the second example, you can replace the second letter 'a' with "abc". String s becomes equal to "aabc". Then the second letter 'a' again. String s becomes equal to "aabcbc". And so on, generating infinitely many different strings.

In the third example, you can either leave string s as is, performing zero moves, or replace the only 'a' with "b". String s becomes equal to "b", so you can't perform more moves on it.

 

其实这到题也不难,就是需要注意的点比较多。 如果代替字符串中有两个字符,并且至少有一个a的时候,就是无限多。如果代替字符串中没有a,那么就是2的n次方个(n是第一行字符串的长度)。剩下的就是1个。

#include<stdio.h>
#include<string.h>
#include<math.h>
int main()
{
    int n;
    char f[100],k[100];
    scanf("%d",&n);
    while(n--)
    {
        int num=0;
        scanf("%s",f);
        getchar();
        scanf("%s",k);
        int len1=strlen(f);              //字符串的长度
        int len2=strlen(k);              //代替字符串的长度
        for(int i=0;i<len2;i++)
        {
            if(k[i]=='a')
                num++;                   //统计代替字符串中a的个数
        }
        if(len2>1&&num>0)                
            printf("-1\n");     //如果代替字符串中有两个字符,并且至少有一个a的时候,就是无限多
        if(len2>=1&&num==0)     //如果代替字符串中没有a,那么就是2的n次方个
            printf("%.0lf\n",pow(2,len1));
        if(len2==1&&num!=0)     //剩余的就1个
            printf("1\n");
    }
    return 0;
}

五.E - Also Try Minecraft.

你正在测试新的秘密Terraria更新。这个更新将在游戏中添加任务!

简单来说,世界地图可以表示为长度为n的数组,其中世界的第i列高度为ai。

你有m个任务需要测试。第j个任务由两个整数sj和tj表示。在这个任务中,你需要从第sj列移动到第tj列。在任务开始时,你出现在第sj列。

在一次移动中,你可以从第x列移动到第x−1列或者第x+1列。在这个版本中,你有幽灵靴,可以让你飞行。由于这是测试版本,它们有bug,所以只有在上飞行时才能飞行,并且飞行持续时间无限。当你从高度为p的列移动到高度为q的列时,你会受到一定的坠落伤害。如果高度p大于高度q,你会受到p−q的坠落伤害,否则你会飞起来并受到0的伤害。

对于给定的每个任务,确定你在完成这个任务时可以受到的最小坠落伤害。

输入

输入的第一行包含两个整数n和m(2≤n≤105;1≤m≤10^5)— 世界中的列数和你需要测试的任务数。

输入的第二行包含n个整数a1,a2,…,an(1≤ai≤10^9),其中ai是世界的第i列的高度。接下来的m
行描述了任务。

第j个任务包含两个整数sj和tj(1≤sj,tj≤n;sj≠tj),表示你需要在第j个任务期间从第sj列移动到第tj列。注意sj可能大于tj。

输出

输出m个整数。其中第j个整数应该是在第j个任务完成时你可以受到的最小坠落伤害。

输入样例

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

输出样例

2
10
0
7
3
1

这题我就比较难受了,交了两遍都超时了,第一种暴力一个一个距离的比较,超时了。然后我又用数组记录下相邻位置的高度差,最后直接相加也超时了。最后,这题应该用前缀和进行处理。(题目没什么难度,读懂题目就进行)

#include<stdio.h>
long long h[200005],dis1[200001],dis2[200001];
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&h[i]);
    for(int i=2;i<=n;i++)
    {
        if(h[i-1]>h[i])                          //如果下降,就记录其下落伤害
            dis1[i]+=dis1[i-1]+h[i-1]-h[i];      //第一个数组按从左到右存储。
        else
            dis1[i]=dis1[i-1];                   //如果上升,就不受到下落伤害
    }
    for(int i=n-1;i>=1;i--)
    {
        if(h[i+1]>h[i])
            dis2[i]=dis2[i+1]+h[i+1]-h[i];       //第二个数组按从右到左存储。
        else
            dis2[i]=dis2[i+1];
    }
    while(m--)
    {
        int x1,x2;
        long long sum=0;
        scanf("%d %d",&x1,&x2);
        if(x2>x1)                               //判断是从左向右还是从右向左。
            sum=dis1[x2]-dis1[x1];
        else
            sum=dis2[x2]-dis2[x1];
        printf("%lld\n",sum);
    }
    return 0;
}
C++

六.F - Summation Game.

爱丽丝和鲍勃正在玩一个游戏。 他们有一个数组 a1,a2,…,an。 游戏包括两个步骤:

首先,爱丽丝将从数组中移除 最多 k 个元素。
其次,鲍勃将把数组中的 最多 x个元素乘以 −1。
爱丽丝希望最大化数组元素的和,而鲍勃希望最小化它。找到游戏结束后数组元素的总和,假设两位玩家都采取最优策略。

输入

每个测试包括多个测试用例。第一行包含一个整数 t(1≤t≤104) — 测试用例的数量。接下来是测试用例的描述。

每个测试用例的第一行包含三个整数 n, k, 和 x (1≤n≤2⋅105, 1≤x,k≤n) — 数组中的元素数量,爱丽丝可以移除的元素数量限制,以及鲍勃可以乘以 −1 的元素数量限制。

每个测试用例的第二行包含 n 个整数 a1,a2,…,an (1≤ai≤1000) — 数组的元素。

保证所有测试用例中 n 的总和不超过 2⋅10^5。

输出

对于每个测试用例,输出一个整数 — 假设两位玩家都采取最优策略后,游戏结束后数组元素的总和。

输入样例

8
1 1 1
1
4 1 1
3 1 2 4
6 6 3
1 4 3 2 5 6
6 6 1
3 7 3 3 32 15
8 5 3
5 5 3 3 3 2 9 9
10 6 4
1 8 2 9 3 3 4 5 3 200
2 2 1
4 3
2 1 2
1 3

输出样例

0
2
0
3
-5
-9
0
-1

这题应该是本次最难的一道题了,其原理类似于贪心,从题目中不难看出,鲍勃的操作其实很好进行,就是找做大的几个数,将它们变为负数(其实就是sum-2*a[i]) ,所以我们仅需要判断爱丽丝的操作即可,其实爱丽丝操作也可以分为抽走0个,1个,2个.......,所以我们只有一一比较,找出最大的即可。

#include<stdio.h>
#include<stdlib.h>
int cmp_int(const void* e1,const void* e2)      //快排的内部比较相邻元素的函数
{
    return *(int*)e2-*(int*)e1;         //表示逆序排序
}
int max(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    int a[200005]={0};
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k,x;
        int sum=0;
        scanf("%d%d%d",&n,&k,&x);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            sum+=a[i];                      //没有进行任何操作前的总和
        }
        qsort(a,n,sizeof(a[0]),cmp_int);    //快排,逆序排序
        for(int i=0;i<x;i++)
            sum-=a[i]*2;                   //爱丽丝抽走0个元素的最后值
        int ans=sum;
        for(int i=0,r=x-1;i<k;i++,r++)
        {
            if(r+1<=n-1)
                ans=ans+a[i]-a[r+1]*2;     //爱丽丝i次抽走元素的最终值
            else
                ans=ans+a[i];
            sum=max(ans,sum);              //依次比较,取最大值
        }
        printf("%d\n",sum);
    }
    return 0;
}

七.G - Very Different Array.

彼特亚有一个长度为ai的整数数组。他的哥哥瓦西亚嫉妒起来,决定自己也要创建一个长度为n的整数数组。

为此,他找到了m个整数bi(m≥n),现在他想从中选择一些整数,并以特定顺序排列它们,以得到一个长度为n的数组ci。

为了避免与他哥哥相似,瓦西亚希望使他的数组与彼特亚的数组尽可能不同。具体来说,他希望总差异D=∑ni=1|ai−ci|尽可能大。

帮助瓦西亚找到他可以获得的最大差异D。

输入

每个测试包含多个测试用例。第一行包含一个整数t(1≤t≤100)—测试用例的数量。接下来是测试用例的描述。

每个测试用例的第一行包含两个整数n和m(1≤n≤m≤2⋅10^5)。

每个测试用例的第二行包含n个整数ai(1≤ai≤10^9)。每个测试用例的第三行包含m个整数bi(1≤bi≤10^9)。

保证在一个测试中,所有测试用例的m之和不超过2⋅10^5。

输出

对于每个测试用例,输出一个整数—可以获得的最大总差异D。

输入样例

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

输出样例

16
0
12
11
10
23
15
25
7

这题其实和刚刚的题目也比较像,将两个数组顺序排列(也可以一个顺序,一个逆序),分两种情况,1.哥最小和妹最大,2.妹最小和哥最大,将1和2的差值最大的每一部分相加,最后得到的就是最大差距。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
long long a[200001],b[200001];
int cmp(const void* e1,const void* e2)      //快速排序内部函数
{ 
    return *(int*)e1-*(int*)e2;            //顺序排序
}
int max(int x,int y)
{
    return x>y?x:y;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        long long sum=0;
        scanf("%d %d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);        //妹妹的数组
        for(int i=0;i<m;i++)
            scanf("%lld",&b[i]);        //哥哥的数组
        qsort(a,n,sizeof(a[0]),cmp);    //对a数组顺序排序
        qsort(b,m,sizeof(b[0]),cmp);    //同理
        for(int i=0;i<n;i++)
        {
            sum+=max(abs(a[i]-b[m-i-1]),abs(a[i]-b[n-i-1]));   //每一部分都取最大
        }
        printf("%lld\n",sum);
    }
    return 0;
}

总结

对于第一次测试,主要是对其思维和阅读理解能力,以及考试心态的测试,同时也帮助我们复习知识,塑造思维模式,掌握思想。学习新知识固然重要,但温故知新的复盘同样是我们在自主学习的大学阶段应该掌握的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值