diff --git a/TangDou/Topic/莫比乌斯函数.cpp b/TangDou/Topic/Mobius/莫比乌斯函数.cpp similarity index 100% rename from TangDou/Topic/莫比乌斯函数.cpp rename to TangDou/Topic/Mobius/莫比乌斯函数.cpp diff --git a/TangDou/Topic/PrefixAndSuffix/P1115.cpp b/TangDou/Topic/PrefixAndSuffix/P1115.cpp new file mode 100644 index 0000000..2805f03 --- /dev/null +++ b/TangDou/Topic/PrefixAndSuffix/P1115.cpp @@ -0,0 +1,21 @@ +#include +using namespace std; +const int N = 1e6 + 10; +const int INF = 0x3f3f3f3f; +int n, a[N], s[N], ans[N]; + +int main() { + cin >> n; + for (int i = 1; i <= n; i++) + cin >> a[i], s[i] = s[i - 1] + a[i]; // 前缀和 + + int mi = 0; + for (int i = 1; i <= n; i++) { + ans[i] = s[i] - mi; + mi = min(mi, s[i]); + } + int res = -INF; + for (int i = 1; i <= n; i++) res = max(res, ans[i]); + cout << res << endl; + return 0; +} \ No newline at end of file diff --git a/TangDou/Topic/PrefixAndSuffix/P3397.cpp b/TangDou/Topic/PrefixAndSuffix/P3397.cpp new file mode 100644 index 0000000..f4717c9 --- /dev/null +++ b/TangDou/Topic/PrefixAndSuffix/P3397.cpp @@ -0,0 +1,28 @@ +#include +using namespace std; + +const int N = 1010; +int b[N][N], s[N][N]; +int n, m; + +int main() { + cin >> n >> m; + while (m--) { + // 从0开始构建差分数组 + int x1, y1, x2, y2; + cin >> x1 >> y1 >> x2 >> y2; + b[x1][y1] += 1; // 进行子矩阵的加减,差分 + b[x2 + 1][y1] -= 1; + b[x1][y2 + 1] -= 1; + b[x2 + 1][y2 + 1] += 1; + } + // 还原为原始数组 + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + s[i][j] = b[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; // 把之前的加减结果进行求和 + printf("%d ", s[i][j]); // 注意输出格式,每个数带一个空格 + } + printf("\n"); // 结束一行的输出输出一个换行符号 + } + return 0; +} \ No newline at end of file diff --git a/TangDou/Topic/前缀和和差分洛谷题单总结.md b/TangDou/Topic/前缀和和差分洛谷题单总结.md new file mode 100644 index 0000000..85da93f --- /dev/null +++ b/TangDou/Topic/前缀和和差分洛谷题单总结.md @@ -0,0 +1,103 @@ +## 前缀和和差分洛谷题单总结 + +[参考文献](https://blog.csdn.net/piqihaoshaonian/article/details/127515000) + +### 一、公式 +#### 前缀和的公式 +一维:$s[i] = a[i] + s[i-1]$ + +二维:$s[i][j] = a[i][j] + s[i-1] [j] + s[ i] [j-1] - s[i-1][j-1]$ + +#### 差分的公式 +一维:$b[i] =s[i] - s[i-1]$ + +二维:$b[i] = s[i][j] - s[i-1][j]-s[i][j-1]+s[i-1][j-1]$ + +### 二、题单 +#### [$P1115$ 最大子段和](https://www.luogu.com.cn/problem/P1115) +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170827397.png) + +**分析** +先求每个位置的前缀和(某个区间求和前缀和可以说是最快的),然后去找该位置前前缀和的最小值,如果要求一段和最大,就要用这段和减去前面最小的值。 + +```cpp {.line-numbers} +#include +using namespace std; +const int N = 1e6 + 10; +const int INF = 0x3f3f3f3f; +int n, a[N], s[N], ans[N]; + +int main() { + cin >> n; + for (int i = 1; i <= n; i++) + cin >> a[i], s[i] = s[i - 1] + a[i]; // 前缀和 + + int mi = 0; + for (int i = 1; i <= n; i++) { + ans[i] = s[i] - mi; + mi = min(mi, s[i]); + } + int res = -INF; + for (int i = 1; i <= n; i++) res = max(res, ans[i]); + cout << res << endl; + return 0; +} +``` + +#### [$P3397$ 地毯](https://www.luogu.com.cn/problem/P3397) +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170847131.png) + +**分析** +看到这里的时候,我就想到了一个矩阵的某个子矩阵进行加减,瞬间想到二维差分和二位前缀和,二位差分的公式为: + +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170848375.png) + +由差分算的二位前缀和公式: +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170849629.png) + +```cpp {.line-numbers} +#include +using namespace std; + +const int N = 1010; +int b[N][N], s[N][N]; +int n, m; + +int main() { + cin >> n >> m; + while (m--) { + // 从0开始构建差分数组 + int x1, y1, x2, y2; + cin >> x1 >> y1 >> x2 >> y2; + b[x1][y1] += 1; // 进行子矩阵的加减,差分 + b[x2 + 1][y1] -= 1; + b[x1][y2 + 1] -= 1; + b[x2 + 1][y2 + 1] += 1; + } + // 还原为原始数组 + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + s[i][j] = b[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1]; // 把之前的加减结果进行求和 + printf("%d ", s[i][j]); // 注意输出格式,每个数带一个空格 + } + printf("\n"); // 结束一行的输出输出一个换行符号 + } + return 0; +} +``` + +### [$P3406$ 海底高铁](https://www.luogu.com.cn/problem/P3406) +![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202312170857701.png) + +**分析** +① 每一段的最小费用加起来则总体费用最小。 + +② 这里的区间是线段而不是一个具体的数,所以我们需要以一个统一的标准进行区间段的区分:于是我们想到了以每个区间的左端点值进行整个线段的记录。 + +③ 节约时间可以对某段区间做同样的加减数的方法:想到的就是差分(当然有差分就会有由差分求前缀和)。 + +④ 最后用得到的线段数比较两种购买方案。 + + +**注意** +当然代码中还有很多需要记录的细节!!!例如:线段数是站点数-1,同时差分和前缀和的循环最好是从1开始(涉及边界问题) \ No newline at end of file