From b548360530109a9c72c3b0abf6985d2fd3331770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Mon, 18 Dec 2023 11:32:32 +0800 Subject: [PATCH] 'commit' --- TangDou/Topic/PrefixAndSuffix/P3406.cpp | 4 +- .../Topic/【前缀和与差分】题单.md | 72 +++++++++---------- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/TangDou/Topic/PrefixAndSuffix/P3406.cpp b/TangDou/Topic/PrefixAndSuffix/P3406.cpp index edb4195..934b122 100644 --- a/TangDou/Topic/PrefixAndSuffix/P3406.cpp +++ b/TangDou/Topic/PrefixAndSuffix/P3406.cpp @@ -16,8 +16,8 @@ signed main() { for (int i = 1; i < m; i++) { // 0号点是出发点,没有意义,不讨论,从1号开始,最大是 m-1 int s = p[i - 1], t = p[i]; // 起点, 终点 - if (s > t) swap(s, t); // 为啥要掉过来呢? - b[s] += 1, b[t] -= 1; // 差分数组处理 + if (s > t) swap(s, t); // 我KAO,原来题意是说:如果你从2~5去则一定走了2,3,4,5这四个城市,铁路按线段处理,即2,3,4号线段 + b[s] += 1, b[t] -= 1; // s在内,t不在内,因为是按线段处理的 } for (int i = 1; i <= n; i++) b[i] += b[i - 1]; // 差分数组变形为前缀和数组 diff --git a/TangDou/Topic/【前缀和与差分】题单.md b/TangDou/Topic/【前缀和与差分】题单.md index 6a760fd..b7a484d 100644 --- a/TangDou/Topic/【前缀和与差分】题单.md +++ b/TangDou/Topic/【前缀和与差分】题单.md @@ -46,7 +46,7 @@ int main() { } ``` -### [$P1083$ [$NOIP2012$ 提高组] 借教室](https://www.luogu.com.cn/problem/P1083) +#### [$P1083$ [$NOIP2012$ 提高组] 借教室](https://www.luogu.com.cn/problem/P1083) #### 暴力 还是先看暴力怎么做吧,对于$m$次借教室,我们可以每次把区间$s\sim t$的空教室数$r-=d$,当有一次$r<0$时,则当前这个人无法被满足,直接输出$-1$和当前这个人的号数,然后直接结束程序。如果$m$次借教室都操作完成后依然没有房间数$r<0$,则说明所有人都可以被满足,则输出$0$。 @@ -179,52 +179,44 @@ signed main() { 发现这些铁路实质上是一维的,并且是关于区间的修改的,那么就可以用差分优化了 ```cpp {.line-numbers} -#include -#include +#include using namespace std; const int N = 100005; -typedef long long ll; -int p[N]; //要访问的城市顺序 -ll a[N]; //买票 -ll b[N]; //充值 -ll c[N]; //买卡 -ll q[N]; //差分数组 -//数据范围是10^5*10^5,所以注意要开ll -int main() -{ - int n, m; - cin >> n >> m; - for (int i = 0;i < m;i++) - cin >> p[i]; //记录访问顺序 - for (int i = 1;i <= n - 1;i++) //输入价格 - cin >> a[i] >> b[i] >> c[i]; - ll res = 0; - for (int i = 1;i < m ;i++) - {//起点到终点,差分修改 - int t1 = p[i - 1]; - int t2 = p[i]; - if (t1 > t2) - q[t2] += 1, q[t1] -= 1; - else - q[t1] += 1, q[t2] -= 1; - } - for (int i = 1;i <=n;i++) - {//前缀和处理 - q[i] += q[i - 1]; - } - for (int i = 1;i <= n-1;i++) - {//判断一下 n*a[i]和n*b[i]+c[i]的大小 - res += min(q[i] * a[i], q[i] * b[i] + c[i]); - } - cout << res; +#define int long long // 数据范围是10^5*10^5,所以注意要开ll +#define endl "\n" +int p[N]; // 要访问的城市顺序 +int x[N], y[N], z[N]; // 买票,充值,买卡 +int b[N]; // 差分数组 +int res; // 结果 +int n, m; // 共n个城市,要去m个城市 + +signed main() { + cin >> n >> m; // 共n个城市,要去m个城市 + for (int i = 0; i < m; i++) cin >> p[i]; // 访问顺序,下标都是从0开始的 + for (int i = 1; i < n; i++) cin >> x[i] >> y[i] >> z[i]; // 每个城市的买票、充值、买卡价格,此处下标从1开始,是因为P0不需要再到P0 + + for (int i = 1; i < m; i++) { // 0号点是出发点,没有意义,不讨论,从1号开始,最大是 m-1 + int s = p[i - 1], t = p[i]; // 起点, 终点 + if (s > t) swap(s, t); // 我KAO,原来题意是说:如果你从2~5去则一定走了2,3,4,5这四个城市,铁路按线段处理,即2,3,4号线段 + b[s] += 1, b[t] -= 1; // s在内,t不在内,因为是按线段处理的 + } + + for (int i = 1; i <= n; i++) b[i] += b[i - 1]; // 差分数组变形为前缀和数组 + + // 判断一下 n*a[i]和n*b[i]+c[i]的大小 + for (int i = 1; i < n; i++) + res += min(b[i] * x[i], b[i] * y[i] + z[i]); + // b[i]:走几次,x[i]*b[i]:买票需要花费多少钱;b[i] * y[i] + z[i]:办卡+冲值共需要花费多少钱 + // 两个打擂台,谁少就用谁,每一块线段都花费最少,整体必须花费最少,贪心 + cout << res << endl; // 输出 } ``` -#### [$P1719$ 最大加权矩阵](https://www.luogu.com.cn/problem/P3406) - -#### [$P2004$ 领地选择](https://www.luogu.com.cn/problem/P2004) #### [$P5638$ 光骓者的荣耀](https://www.luogu.com.cn/problem/P5638) +#### [$P1719$ 最大加权矩阵](https://www.luogu.com.cn/problem/P3406) + +#### [$P2004$ 领地选择](https://www.luogu.com.cn/problem/P2004) #### [$P3397$ 地毯](https://www.luogu.com.cn/problem/P3397)