diff --git a/TangDou/Topic/PrefixAndSuffix/P5638.cpp b/TangDou/Topic/PrefixAndSuffix/P5638.cpp index 5d67bc3..84ad89c 100644 --- a/TangDou/Topic/PrefixAndSuffix/P5638.cpp +++ b/TangDou/Topic/PrefixAndSuffix/P5638.cpp @@ -1,22 +1,24 @@ #include using namespace std; -const int N = 1000010; #define int long long #define endl "\n" +const int N = 1000010; +int n, k; int a[N], s[N]; -int n, k; // n个城市,传送半径为k -int res; +int ans = LONG_LONG_MAX; // 预求最小先设最大 + signed main() { - cin >> n >> k; // n个城市,传送半径为k - for (int i = 1; i < n; i++) { // 以起点为线段命名的编号,所以1~n共n个城市,其实是n-1条线段 - cin >> a[i]; // 走这条路要耗费时间a[i] - s[i] += s[i - 1] + a[i]; // 前缀和 + cin >> n >> k; + for (int i = 2; i <= n; i++) { // i代表第i个城市 + cin >> a[i]; // a[i]代表第i-1个城市到第i个城市需要的时间 + s[i] = s[i - 1] + a[i]; // 利用前缀存储从第1个城市到第i+1个城市的累积时间 + } + // 感悟:代码越多,可读性越强 + for (int i = 1; i <= n; i++) { // 遍历每个城市 + int far = i + k; // 传送到最远的点 + if (far >= n) far = n; // 最远不能超过n点 + int time = s[i] + s[n] - s[far]; // s[n]-s[far]= 剩余道路需要走的时间,s[i]:前面道路需要走的时间 + ans = min(ans, time); // 取最小值 } - /* - 1、找出[1,n-1]的原始数组中,长度为k的子区间,加法和最大的区间段 - 2、注意:如果是枚举原始数组,那么就是 [1,n-k]是有效区间 - 3、现在遍历的是前缀和数组,为了表示a[1],需要使用的是s[1]-s[0],所以,i从0开始 - */ - for (int i = 0; i + k < n; i++) res = max(res, s[i + k] - s[i]); - cout << s[n - 1] - res << endl; + cout << ans << endl; // 输出 } \ No newline at end of file diff --git a/TangDou/Topic/【前缀和与差分】题单.md b/TangDou/Topic/【前缀和与差分】题单.md index dd9c9bc..ba476bd 100644 --- a/TangDou/Topic/【前缀和与差分】题单.md +++ b/TangDou/Topic/【前缀和与差分】题单.md @@ -226,28 +226,51 @@ signed main() { **思路** -这是一道难度入门的良心题~ +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312181353674.png) -题意很明了,可以传送一次,求$1$到$n$耗费的最少时间 +上图是一个$n = 6$的样例。从城市$1$到城市$6$,需要$3+2+4+5+4=18$天。 -很明显,可以贪心,最长的$k$段选择传送,其余步行 +假如传送器的半径为$2$。可以逐个枚举。 -求两地之间用时使用前缀和,$s[i]$表示$a_1$到$a_i$之和 +- 如果在城市$1$使用传送器,则一下子可到达城市$3$,然后城市$3$到城市$6$,需要$13$天。这种情况下从城市$1$到城市$6$,需要$13$天。 -那么使用传送器可以节省时间可表示为$s[k+i]-s[i]$ (有效区间$[i+1,i+k]$) +- 如果在城市$2$使用传送器,则从城市$1$先用$3$天的时间到达城市$2$,再用传送器到达城市$4$,从城市$4$到城市$6$需要$9$天。这种情况下从城市$1$到城市$6$,共需要$3 + 9 = 12$天。 -扫一遍找到节省时间最大值,答案即是$1$到$n$之间步行用时减去传送节省时间 -然而稍不注意就只有$92$分,似乎坑到了一部分人(比如本蒟蒻) +- 如果在城市$3$使用传送器,则从城市$1$到城市$3$需要$5$天,从城市$3$使用传送器一下子到达城市$5$,从城市$5$到城市$6$需要$4$天。这种情况下从城市$1$到城市$6$,共需要$5+4=9$天。 -![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312181334534.png) +- 如果在城市$4$使用传送器,则从城市$1$到城市$4$需要$9$天,从城市$4$使用传送器一下子到达城市$6$。这种情况下从城市$1$到城市$6$,共需要$9$天。 -原因很简单,$s[k+i]-s[i]$中的$i$要从$0$开始循环而不是从$1$开始 -显而易见,若$k=1$,那么$s[1+1]-s[1]$表示的是$2 , 3$两地之间用时 -所以如果从$1$开始循环就会漏掉从$1$地到$1+k$地之间的用时 -从$0$开始循环就可以$AC$了! +- 如果在城市$5$使用传送器,则从城市$1$到城市$5$需要$14$天,从城市$5$使用传送器一下子到达城市$6$。这种情况下从城市$1$到城市$6$,共需要$14$天。 +所以在城市$3$或城市$4$使用传送器,可以使得总共花费的时间最少。 +**$Code$** +```cpp {.line-numbers} +#include +using namespace std; +#define int long long +#define endl "\n" +const int N = 1000010; +int n, k; +int a[N], s[N]; +int ans = LONG_LONG_MAX; // 预求最小先设最大 +signed main() { + cin >> n >> k; + for (int i = 2; i <= n; i++) { // i代表第i个城市 + cin >> a[i]; // a[i]代表第i-1个城市到第i个城市需要的时间 + s[i] = s[i - 1] + a[i]; // 利用前缀存储从第1个城市到第i+1个城市的累积时间 + } + // 感悟:代码越多,可读性越强 + for (int i = 1; i <= n; i++) { // 遍历每个城市 + int far = i + k; // 传送到最远的点 + if (far >= n) far = n; // 最远不能超过n点 + int time = s[i] + s[n] - s[far]; // s[n]-s[far]= 剩余道路需要走的时间,s[i]:前面道路需要走的时间 + ans = min(ans, time); // 取最小值 + } + cout << ans << endl; // 输出 +} +``` #### [$P1719$ 最大加权矩阵](https://www.luogu.com.cn/problem/P3406)