一篇征文
(图片放不出来,不知道为什么会违规)
刷题
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;
}