程序设计语言综合设计(第 2 章)

  • 第 2 章
    • 2_Store Vayh_E的便利店
    • 2_string Vayh_E and String
    • 2_Rectangles Vayh_E and Rectangles
    • 2_art_exhibition 画展
    • 2_You_ jump_I_ jump
    • 2_You_ jump_I_ jump_2
    • 2_Continuous_period 连续数字段
    • 2_You_ jump_I_ jump_3

第 2 章

2_Store Vayh_E的便利店

实验任务

  Vayh_Eayh_E 最近 开了一家便利店,然而让他头疼的是分析营业情况这一工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定波动大减价或者是其他情况的时候,营业额会出现一定波动 ,当然一定的波动还是能够接受的。但是在某些时候营业额突变得很高或低,这就证明此时的经营状况出现了问题。

  现在定义最小波动值来衡量这种情况 :第 i 天的最小波动值为 【前面 i-1天中,与第 i天营业额的差值绝对的最小值】,且规定第 1 天的最小波动值为第 1 天的营业额。(参考样例 Hint )

  Vayh_Eayh_E 看着最近 n天的销售情况有点发愁,你能帮他算出这 n 天的最小波动值的总和吗 ?

数据输入

  第一行个正整数 n(1<=n <=1 00) ,表示天数为 n。
  第二行为 n 个整数, 第 i 个数表示第 i 天的营业额 a[i],a[i]<=100

数据输出

  输出一个数,表示这 n 天的最小波动值的总和。

样例

输入示例

6
5 1 2 5 4 6

输出示例

12

Hint

第 1 天的最小波动值: 5
第 2 天的最小波动值: |1 - 5| = 4
第 3 天的最小波动值: |2 - 1| = 1
第 4 天的最小波动值: |5 - 5| = 0
第 5 天的最小波动值: |4 - 5| = 1
第 6 天的最小波动值: |6 - 5| = 1
这 6 天的最小波动值总和为: 5+4+1+0+1+1 = 12


Code:

#include 
#include 
int main (void)
{
    short i,j;
    short n;
    short a[110];
    scanf("%hd",&n);
    scanf("%hd",&a[1]);         //直接读取a[1],将第一天的营业额直接作为最小波动值总和的初值
    short tot=a[1];             //tot为最小波动值总和,初值直接设为第一天的营业额
    for (i=2;i<=n;i++)
    {
        scanf("%hd",&a[i]);
        short min=1000;
        for (j=1;j<=i-1;j++)    //从1到i-1循环,取最小波动值
        {
            short t=fabs(a[i]-a[j]);
            if (tprintf("%d\n",tot);
    return 0;
}

2_string Vayh_E and String

实验任务

  星期四晚上,Vayh _E 抬头想着接下来三天空的课表莫名感到兴奋,然而回过神来一低头,就深感到被作业支配的恐惧。
  最让他头疼的就是字符串这东西啦。现在他有一个由 n 个小写字母组成的符串 str, 从左到右对每个字母进行编号 1…n 。接下来他要对这个字符串依次进行 m 次操作,每次操作为: 选择一个正整数 a[i],然后将编号为 a[i]到 n-a[i]+1的这一段字母进行反转。Vayh _E 负责头疼,你负责帮他解决这个问题吧 :经过m次操作,最后得到的字符串是什么样的?

数据输入

  第一行为两个正整数 n,m。
  第二行为长度 n 的字符串。
  第三行为 m 个正整数,第 i 个整数为 a[i],表示对字符串编号为 a[i] 到 n-a[i]+1 的这一 段字母进行反转( 编号从 1 开始 ),题目保证 2*a[i]<=n

数据范围 :
  对于 50% 的数据, n, m<=10
  对于 80% 的数据, n, m<=1000
  对于 100% 的数据 ,n,m<=100000

数据输出

  输出一个 字符串,为经过 m 次反转操作后的字符串

样例

输入示例

6 1
abcdef
2

输出示例

aedcbf

输入示例

6 3
abcdef
1 2 3

输出示例

fbdcea

输入示例

5 2
vwxyz
2 2

输出示例

vwxyz

Hint

样例1:

  abcdef

  2:对编号[2, 5]的字母进行反转=>aedcbf

样例2:

  abcdef

  1:对编号[1, 6]的字母进行反转=>fedcba

  2:对编号[2, 5]的字母进行反转=>fbcdea

  3:对编号[3, 4]的字母进行反转=>fbdcea

样例3:

  vwxyz

  2:对编号[2, 4]的字母进行反转=>vyxwz

  2:对编号[2, 4]的字母进行反转=>vwxyz


Code

#include 
#include 
#include 
using namespace std;
int main (void)
{
    int n,m,i,b[100010],a[100010];  //b[]存放m个反转起点,a[i]表示第i个起点到下一个起点之间的字符串反转过几次
    char s[100010],str[100010];
    memset(a,0,sizeof(a));
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    for (i=0;iscanf("%d",&b[i]);
    sort(b,b+m);            //对反转起点从小到大排序
    for(i=0;i1]=i+1;      //因为已经排序,所以i+1即为字符串的第b[i]-1位到下一起点间字符串的反转次数

    int mid=n/2+1,ok=0,k=-1;
    for(i=0;iif (a[i]!=k && a[i]!=0) //当a[i]发生改变且非0时,即到了下一个反转起点
        {
            k=a[i];
            ok=a[i]%2;  //利用奇偶判断此时字符是否需要反转
        }
        if (ok)
        {   //如果为奇数,则需要反转,交叉赋值。
            str[i]=s[n-1-i]; str[n-1-i]=s[i];
        }
        else
        {   //如果为偶数,则无需反转,原样赋值。
            str[i]=s[i]; str[n-1-i]=s[n-1-i];
        }
    }
    printf("%s\n",str);

    return 0;
}

因为对称性,且起点先后顺序不影响结果,所以只需记录下反转起点(需从小到大排序)到下一起点间字符串所需的反转次数,再根据奇偶性,即可知此段字符串需原样输出还是反转输出。


2_Rectangles Vayh_E and Rectangles

实验任务

  Vayh_E 有 n 个矩形, 每个矩形在二维坐标上表示为 (i, j, k) ,代表矩形左下角的点的坐标为 (i, 0),右上角的点坐标为 (j, k) 。现在 ,将这 n 个矩形绘在坐标纸上,最终得到的面积是多少呢?

数据输入

  第一行为两个 正整数 n(1<=n<=100 )。
  接下来有 n 行,每行包括 3 个非负整数 i, j, k(0<=i

4
0 2 3
0 3 1
1 2 2
2 4 4

输出示例

14

Code

#include 
#include 
int main (void)
{
    short n,i,j,k,a,x,y;
    scanf("%hd",&n);

    short area[110][110],max_x=-1,max_y=-1;
    memset(area,0,sizeof(area));
    for (a=1;a<=n;a++)
    {
        scanf("%hd%hd%hd",&i,&j,&k);
        if (j>max_x)                //求矩形出现的最大范围
            max_x=j;
        if (k>max_y)
            max_y=k;
        for (y=1;y<=k;y++)
            for (x=i+1;x<=j;x++)
                area[y][x]=1;       //所有属于矩形内的方格赋值为1
    }

    short num=0;
    for (y=1;y<=max_y;y++)
        for (x=1;x<=max_x;x++)
            if (area[y][x])
                num++;              //在最大范围内,将值为1的方格相加,即得到面积
    printf("%d\n",num);
    return 0;
}

用一个二维数组area[y][x]表示坐标为(x,y),面积为1的方格。(i,j,k)表示一个右上角方格坐标为(j,k),左下角方格坐标为(i+1,1) 的矩形。


2_art_exhibition 画展

实验任务

  Vayh_E 忙里偷闲 ,叫上了他的朋友 Anani_leaf 一起 去看一场画展。画展上有 n 幅画 ,第 i 幅画有精美值 a[i]。
  我们知道 ,当游客在看到一幅精美值比前一幅画更高的作品时,就会感到满意。换句话来说,如果游客欣赏到第 i+1幅画 ,且 a[i+1] > a[i],那么游客就会感到满意。
  Vayh_E 和 Anani_leaf 想知道他们以某种顺序欣赏这些画所能得到最多的满意次数是多少。
  难得来一次画展,他们俩更想好欣赏这些画, 所以, 这个任务就交给你啦 ~

数据输入

  第一行个正整数 n(1<=n <=1 000) ,表示 一共有 n 幅画 。
  第二行为 n 个正整 数, 第 i 个数表示第 i 幅画的精美值 a[i],1<= a[i]<=1000

数据输出

  输出一个数, 表示以某种顺序欣赏这些画所能得到最多的满意次数

样例

输入示例

5
20 30 10 50 40

输出示例

4

输入示例

4
200 100 100 200

输出示例

2

Hint

样例 1:
  得到最多满意次数的欣赏顺序:10 20 30 40 50,满意次数为4次
样例 2:
  得到最多满意次数的欣赏顺序:100 200 100 200,满意次数为2次


Code

#include 
#include 
int main (void)
{
    short n,i,j;
    short a[1010];      //a[i]表示数字i出现了a[i]次
    memset(a,0,sizeof(a));
    scanf("%hd",&n);
    for (i=0;ishort temp;
        scanf("%hd",&temp);
        a[temp]++;          //读取数temp,temp出现次数+1
    }

    int sum=0;
    for (i=1;i<=1000;i++)   //求出现次数在i次及以上的数字个数
    {
        short num=-1;       //满意度为序列长度-1,所以num初值为-1
        for (j=1;j<=1000;j++)   //数字范围在1000以内,所以从1到1000寻找出现次数符合条件的数字
            if (a[j]>=i)
                num++;
        if (num<1) break;   //当序列长度小于2,则无满意度,此时可退出循环
        sum+=num;
    }
    printf("%d\n",sum);
    return 0;
}

寻找所有数中一列最长不重复的子序列(长度>1),则此序列满意度为序列长度减一,然后在剩下的数字中同样再找最长不重复的子序列,以此类推,直至序列长度小于等于1。

将数字出现次数用 a[] 储存,a[] 的下标即为这个数字,然后 i 从 1 开始循环,求出现次数在 i 次及以上的数字的个数,则满意次数为数字个数减一,然后 i 从 2 开始,以此类推,直到某次循环数字个数小于 2 ,即无满意度,则退出循环。


2_You_ jump_I_ jump

实验任务

  “Youjump, I jump.”刚看完 Titanic 的 Anani_leaf 被这句台词深深震撼。ta 赶忙拉来 Vayh_E 想重现这一幕,然而遭到了 Vayh_E 赤裸裸的拒绝,“不来不来”。为了不太过打击 Anani_leaf,Vayh_E 提出了一个新游戏:jump game

  给定一个含有 n 个数的数组,且数组的每个元素均为非负整数,从左往右,第 i 个数为 a[i](1<=i<=n),代表在该位置可以向某个方向跳 a[i] 步。一开始 Vayh_E 在下标为 1 的位置,Anani_leaf 在下标为 n 的位置。如果 Vayh_E 一直往右跳,Anani_leaf 一直往左跳,那么最后俩人能到达数组的另一端吗?(即 Vayh_E 能否到达 n ,Anani_leaf 能否到达 1 )

数据输入

  第一行一个正整数n(1<=n<=1000),表示有 n 个位置(从1到n)。

  第二行为 n 个非负整数,第 i 个数表示第 i 个位置能跳 a[i] 步,0<=a[i]<=1000

  一开始 Vayh_E 在下标为 1 的位置,Anani_leaf 在下标为 n 的位置。

数据输出

  输出一行,如果Vayh_E能到达n,而且Anani_leaf能到达1,那么输出“Yes”(不含引号);否则输出“No”(不含引号)

样例

输入示例

5
2 3 1 1 4

输出示例

Yes

输入示例

5
2 3 1 1 5

输出示例

No

输入示例

5
2 3 1 2 4

输出示例

No

输入示例

5
2 3 1 2 5

输出示例

No

Hint

样例1:

  Vayh_E的位置变化为:1=>3=>4=>5

  Anani_leaf的位置变化为:5=>1

  因此为Yes

样例2:

  Vayh_E的位置变化为:1=>3=>4=>5

  Anani_leaf的位置变化为:5=>0,超出范围

  因此为No

样例3:

  Vayh_E的位置变化为:1=>3=>4=>6,超出范围

  Anani_leaf的位置变化为:5=>1

  因此为No

样例4:

  Vayh_E的位置变化为:1=>3=>4=>6,超出范围

  Anani_leaf的位置变化为:5=>0,超出范围

  因此为No


Code

#include 
int main (void)
{
    short n,i;
    scanf("%hd",&n);
    short a[1010];
    for (i=1;i<=n;i++)
        scanf("%hd",&a[i]);

    short ok_1=0,ok_2=0;
    short v=1;
    while (v<=n)
    {
        if (v==n)   //当V==n时,说明Vayh_E能到达 n,ok_1=1,退出循环。
        {           //若因为v>n而退出循环,则ok_1==0;
            ok_1=1;
            break;
        }
        if (a[v]==0)    //如果当前位置a[v]==0,则无法继续跳,直接输出No
        {
            printf("No\n");
            return 0;
        }
        v+=a[v];
    }
    short an=n;
    while (an>=1)   //同上
    {
        if (an==1)
        {
            ok_2=1;
            break;
        }
        if (a[an]==0)
        {
            printf("No\n");
            return 0;
        }
        an-=a[an];
    }
    if (ok_1 && ok_2)       //当两个条件都符合,即输出YES
        printf("Yes\n");
    else
        printf("No\n");

    return 0;
}

2_You_ jump_I_ jump_2

实验任务

  玩了好几把 jump game 之后,Anani_leaf 觉得这个游戏太简单了一点都没有挑战性,因此他将规则做了一点小小的改动。

  给定一个含有 n 个数的数组,且数组的每个元素均为非负整数,从左往右,第 i 个数为 a[i](1<=i<=n),代表在该位置可以向某个方向跳不超过 a[i] 步。一开始 Anani_leaf 在下标为 1 的位置,如果 Anani_leaf 一直往右跳,那么最后 ta 能到达 n 的位置吗?

数据输入

  第一行一个正整数 n,表示有 n 个位置(从 1 到 n )。

  第二行为 n 个非负整数,第 i 个数表示第 i 个位置能跳不超过 a[i] 步,0<=a[i]<=n

  一开始 Anani_leaf 在下标为 1 的位置,且 ta 一直往右跳。

  对于80%的数据,n<=100

  对于100%的数据,n<=100000

数据输出

  输出一行,如果 Anani_leaf 能到达 n,那么输出“Yes”(不含引号);否则输出“No”(不含引号)

样例

输入示例

5
2 3 1 1 4

输出示例

Yes

输入示例

5
2 1 1 2 4

输出示例

Yes

输入示例

5
3 2 1 0 4

输出示例

No

Hint

样例1:

  Anani_leaf 的一种可行位置变化为:1=>2=>5

样例2:

  Anani_leaf 的一种可行位置变化为:1=>3=>4=>5

样例3:

  Anani_leaf 无法到达 n


Code

#include 
int main (void)
{
    int n,i,j,a[100010];
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for (i=1;i//从1到n-1寻找值为0的数,而n==0则没关系
    {
        if (a[i]==0)
        {
            short ok=0;
            for (j=i-1;j>=1;j--)    //找到后,往前寻找是否有数的值大于两点之间的距离
            {
                if (a[j]>i-j)
                {
                    ok=1;
                    break;
                }
            }
            if (!ok)
            {
                printf("No\n");
                return 0;
            }
        }
    }
    printf("Yes\n");
    return 0;
}

本质即是寻找数组中a[i]==0的位置,并从此处往前找是否有数的值 a[j] 大于此数和0的位置差距,如果有,说明可跨过 a[i]==0 的这个位置,若没有,则说明无法跨过这个位置,即无法到达 n。


2_Continuous_period 连续数字段

实验任务

  百无聊赖的 Vayh_E 看着 Anani_leaf 沉迷于 ta 的 jumpgameⅡ ,决定找点事情消磨时间。

  Vayh_E 随手用计算机生成一组大小为 n 的数组,包含 n 个不相同的递增的整数。他想知道这 n 个数组成了哪些连续的数字段。你也来练练手吧~

数据输入

  第一行一个正整数 n(1<=n<=1000),表示有 n 个数。

  第二行为 n 个整数,第 i 个整数为 a[i],0<=a[i]<=10000

数据输出

  第一行输出一个数 k ,为 n 个数组成的连续数字段的段数

  接下来 k 行,从小到大输出每一段连续数字段的区间(格式为[L,R],参考输出样例)

样例

输入示例

6
0 1 2 4 5 7

输出示例

3
[0,2]
[4,5]
[7,7]

输入示例

6
0 1 2 3 4 5

输出示例

1
[0,5]

输入示例

6
0 2 4 6 8 10

输出示例

6
[0,0]
[2,2]
[4,4]
[6,6]
[8,8]
[10,10]

Code

#include 
#include 
int main (void)
{
    short n,i,j,a[1010];
    scanf("%hd",&n);
    for (i=1;i<=n;i++)
        scanf("%hd",&a[i]);

    char s[1010][15];
    short num=0;
    i=1;            //起点i=1;
    while (ifor (j=i+1;j<=n;j++)
        {
            if (a[j]!=a[j-1]+1)     //找到某个数与前一个数不连续
            {
                num++;          //段数+1
                sprintf(s[num],"[%d,%d]\n",a[i],a[j-1]); //输出从起点到j-1的数字段,将输出内容存入s[num]中
                i=j;        //j作为新的起点
                if (i==n)   //如果这个不连续的点恰好为a[n],则直接输出[n,n],输出内容存入s[num]中
                {
                    num++;
                    sprintf(s[num],"[%d,%d]\n",a[i],a[i]);
                }
                break;
            }
            if (j==n)       //如果这个点是连续的,且恰好为n,则输出[a[i],a[n]],输出内容存入s[num]中
            {
                num++;
                sprintf(s[num],"[%d,%d]\n",a[i],a[j]);
                i=j;
            }
        }
    }

    printf("%d\n",num);     //先输出段数
    for (i=1;i<=num;i++)
        printf("%s",s[i]);  //再依次输出各段字符串

    return 0;
}

从 i==1 开始,寻找某个数 a[j] 满足 a[j]!=a[j-1]+1,即 a[j] 与前数不连续,找到后,输出前面的数字段,并将起点 i 定为 j ,接着循环,直至结束。

//sprintf(s,”…”,…)

//把格式化的数据写入 s 字符串中


2_You_ jump_I_ jump_3

实验任务

  Anani_leaf回过头来发现Vath_E在孤零零的玩着,于心不忍。于是ta再次修改了ta的jump game规则:

  一个圈由n个格子围成,一开始(0 minutes)他们俩都站在start的位置。接下来每分钟Anani_leaf顺时针往前跳A格,然后将ta所处的那一格涂成红色;Vayh_E顺时针往前跳B格,然后将他所处的那一格涂成绿色。当某一个格子被涂上两种颜色时,游戏结束。

  Anani_leaf拉来Vayh_E玩得正high。现在,给定n、A和B,你能确定游戏在第几分钟的时候结束嘛?

数据输入

  输入包括三个整数n、A、B。(1<=n, A, B<=10000)

数据输出

  输出一个整数t,表示游戏在第t分钟结束

样例

输入示例

8 2 3

输出示例

3

Hint


Code

#include 
#include 
int main (void)
{
    short n,a,b,space[10010];
    memset(space,0,sizeof(space));
    scanf("%hd%hd%hd",&n,&a,&b);
    short ok=1,time=0,site_a=0,site_b=0;
    while (ok)
    {
        time++;
        site_a=(site_a+a)%n;        //a的位置有可能超过格子长度,所以计算a的当前位置时要对格子长度取余
        if (space[site_a]==1)       //若发现这个格子已经被涂过颜色
        {
            printf("%d\n",time);    //则输出时间,退出程序
            return 0;
        }
        else
            space[site_a]=1;        //否则,将此格子标记

        site_b=(site_b+b)%n;        //同上
        if (space[site_b]==1)
        {
            printf("%d\n",time);
            return 0;
        }
        else
            space[site_b]=1;
    }

    return 0;
}

你可能感兴趣的:(题解)