2022.10.09

一篇征文

(图片放不出来,不知道为什么会违规)

 刷题

P2242 公路维修问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

由于长期没有得到维修,A国的高速公路上出现了 n 个坑。为了尽快填补好这 n 个坑,A国决定对 m 处地段采取交通管制。为了求解方便,假设A国的高速公路只有一条,而且是笔直的。现在给出 n 个坑的位置,请你计算,最少要对多远的路段实施交通管制?

输入格式

输入数据共两行,第一行为两个正整数 n, m(2≤m≤n≤15000)。第二行给出了 n 个坑的坐标(坐标值均在长整范围内,按从小到大的顺序给出,且不会有两个点坐标相同)。

输出格式

仅一行,为最小长度和。

输入输出样例

输入

18 4
3 4 6 8 14 15 16 17 21 25 26 27 30 31 40 41 42 43

输出

25

说明/提示

[样例说明]

交通管制的地段分别为:3-8,14-21,25-31,40-43。

思路

题目的意思就是将n个地点分成m段。题目要求进行交通管制的路径长度尽可能短,所以我们就是需要从所有的两个地点之间的距离中选取m-1个最长的距离即可。

代码实现

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n,m,a[15005],b[15005];
    scanf("%lld %lld",&n,&m);//坐标值均在长整范围内
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
    }
    long long sum=0;
    for(int i=1;i<n;i++)
    {
        b[i-1]=a[i]-a[i-1];//获得每两个相邻的地点之间距离只差
    }
    sort(b,b+n);//从小到大排序
    for(int i=0;i<n-m+1;i++)//排除最大的m-1段距离
    {
        sum+=b[i];
    }
    printf("%lld",sum+m);//每一段距离等于,两个地点的坐标相减再加一,有m段,所以再加m
    return 0;
}

P1176 路径计数2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

一个N×N的网格,你一开始在(1,1),即左上角。每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法。

但是这个问题太简单了,所以现在有M个格子上有障碍,即不能走到这M个格子上。

输入格式

输入文件第1行包含两个非负整数N,M,表示了网格的边长与障碍数。

接下来M行,每行两个不大于N的正整数x, y。表示坐标(x, y)上有障碍不能通过,且有1≤x, y≤n,且x, y至少有一个大于1,并请注意障碍坐标有可能相同。

输出格式

一个非负整数,为答案mod100003后的结果。

输入输出样例

输入 #1

3 1
3 1

输出 #1

5

说明/提示

对于20%的数据,有N≤3;

对于40%的数据,有N≤100;

对于40%的数据,有M=0;

对于100%的数据,有N≤1000,M≤100000。

思路

本质上是一个简单的dp,所以就有状态转移方程,b[i][j]=(b[i-1][j]%100003+b[i][j-1]%100003)%100003,该点的左侧的点加上方的点的方法数之和,最后输出终点位置的方法数的值。

代码实现

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[1005][1005],b[1005][1005],n,m;//数组a记录通路或障碍,数组b记录方法的数量
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)//初始化,所有都为通路,以及每个地点的方法数为0
    {
        for(int j=1;j<=n;j++)
        {
            a[i][j]=0;
            b[i][j]=0;
        }
    }
    for(int i=0;i<m;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);//障碍
        a[x][y]=1;
    }
    b[1][1]=1;//初始化到起点的方法,很重要
    for(int i=2;i<=n;i++)//初始化边界上的点
    {
        if(a[i][1]==1)
        {
            b[i][1]=0;
        }
        else
        {
            b[i][1]=b[i-1][1]%100003;
        }
        if(a[1][i]==1)
        {
            b[1][i]=0;
        }
        else
        {
            b[1][i]=b[1][i-1]%100003;
        }
    }
    for(int i=2;i<=n;i++)//初始化中间的点
    {
        for(int j=2;j<=n;j++)
        {
            if(a[i][j]==0)
            {
                b[i][j]=(b[i-1][j]%100003+b[i][j-1]%100003)%100003;
            }
        }
    }
    printf("%d",b[n][n]%100003);
    return 0;
}

P2004 领地选择 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

作为在虚拟世界里统帅千军万马的领袖,小 Z 认为天时、地利、人和三者是缺一不可的,所以,谨慎地选择首都的位置对于小 Z 来说是非常重要的。

首都被认为是一个占地 C×C 的正方形。小 Z 希望你寻找到一个合适的位置,使得首都所占领的位置的土地价值和最高。

输入格式

第一行三个整数 N,M,C,表示地图的宽和长以及首都的边长。

接下来 N 行每行 M 个整数,表示了地图上每个地块的价值。价值可能为负数。

输出格式

一行两个整数 X,Y,表示首都左上角的坐标。

输入输出样例

输入 #1

3 4 2
1 2 3 1
-1 9 0 2
2 0 1 1

输出 #1

1 2

说明/提示

对于 60% 的数据,N,M≤50。

对于 90% 的数据,N,M≤300。

对于 100% 的数据,1≤N,M≤103,1≤C≤min(N,M)。

 思路

这题本质是一个dp,然后加了一点其他的东西。

图的坐标是从(1,1)算起。

对于(1,1)这个点,就直接算。

对于位于第一列的点(j=1)的点,除了(1,1),是加上下面新增的一部分,减去上面不要的一部分,如图就是减去棕色部分,加上浅蓝色部分。

对于其他的位置,是加上右边新增的一部分,减去左边不要的一部分,如图中,就是减去黄色部分,加上绿色部分。

代码实现

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,m,c,a[1005][1005],b[1005][1005];
    scanf("%d %d %d",&n,&m,&c);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1;i<=n-c+1;i++)
    {
        for(int j=1;j<=m-c+1;j++)
        {
            if(i==1&&j==1)//(1,1)面积
            {
                for(int e=1;e<=c;e++)
                {
                    for(int f=1;f<=c;f++)
                    {
                        b[i][j]+=a[e][f];
                    }
                }
            }
            else if(j==1)//第一列是加上下面新增的一部分,减去上面不要的一部分
            {
                int sum=0;
                for(int e=1;e<=c;e++)
                {
                    sum+=(a[i+c-1][e]-a[i-1][e]);
                }
                b[i][j]=b[i-1][j]+sum;
            }
            else//其余点就是加上右边新增的一部分,减去左边不要的一部分
            {
                int sum=0;
                for(int e=i;e<=i+c-1;e++)
                {
                    sum+=(a[e][j+c-1]-a[e][j-1]);
                }
                b[i][j]=b[i][j-1]+sum;
            }
        }
    }
    int x=1,y=1;//初始化最大值为(1,1)
    for(int i=1;i<=n-c+1;i++)//找最大值
    {
        for(int j=1;j<=m-c+1;j++)
        {
            if(b[i][j]>b[x][y])
            {
                x=i;
                y=j;
            }
        }
    }
    printf("%d %d",x,y);
    return 0;
}

题目背景

小 W 下载了一款运动软件。

题目描述

小 W 准备在接下来的 m 天中锻炼,由于他不能走得太多以至于累死(怎么可能呢),所以他这 m 天最多一共只能走 n 步。
这个运动软件为了激励小 W 走路,推出了 k 种激励措施,每种激励措施都形如“如果你第 p 天走完了 q 步,那么第 p 天中接下来的每一步都会给你加 1 积分”。激励措施可以叠加,即走一步你可能可以获得多于 1 积分。
现在小 W 想知道,他最多可以获取多少积分呢?

输入格式

第一行三个整数 n,m,k,意义如上。
接下来 k 行,每行两个整数 p,q,表示一个激励措施,意义如上。

输出格式

一行 1 个整数,表示 m 天后最多可以获得的积分。

输入输出样例

输入 #1

5 1 3
1 0
1 2
1 4

输出 #1

9

说明/提示

样例解释:
只有一种方案,即在第一天走 5 步,第一、二步各获得 1 积分,第三、四步各获得 2 积分,第五步获得 3 积分,总计 9 积分。


数据范围:
对于 10% 的数据,n,m,k≤10。
对于 40% 的数据,n,m,k≤103。
对于 100% 的数据,1≤n≤1012,1≤m,k≤10^5,1≤p≤m,0≤q≤n。

思路 

这一题本质是贪心。“如果你第 p 天走完了 q 步,那么第 p 天中接下来的每一步都会给你加 1 积分”,然后我们有需要获得最多的积分,所以需要在一天之内走完全部的步数,超过的步数就会获得额外的奖励,从而得到最多的积分。

代码实现

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n,m,k,x,y,a[100005];//注意数据范围
    for(int i=0;i<100005;i++)//初始化
    {
        a[i]=0;
    }
    scanf("%lld %lld %lld",&n,&m,&k);
    for(int i=0;i<k;i++)
    {
        scanf("%lld %lld",&x,&y);
        if(n-y>0)//当天获得奖励
        {
            a[x]+=n-y;
        }
    }
    long long Max=a[1];
    for(int i=2;i<m;i++)
    {
        if(a[i]>Max)
        {
            Max=a[i];
        }
    }
    printf("%lld",Max);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值