语文成绩
题目背景
语文考试结束了,成绩还是一如既往地有问题。
题目描述
语文老师总是写错成绩,所以当她修改成绩的时候,总是累得不行。她总是要一遍遍地给某些同学增加分数,又要注意最低分是多少。你能帮帮她吗?
输入格式
第一行有两个整数 n n n, p p p,代表学生数与增加分数的次数。
第二行有 n n n 个数, a 1 ∼ a n a_1 \sim a_n a1∼an,代表各个学生的初始成绩。
接下来 p p p 行,每行有三个数, x x x, y y y, z z z,代表给第 x x x 个到第 y y y 个学生每人增加 z z z 分。
输出格式
输出仅一行,代表更改分数后,全班的最低分。
样例 #1
样例输入 #1
3 2
1 1 1
1 2 1
2 3 1
样例输出 #1
2
提示
对于 40 % 40\% 40% 的数据,有 n ≤ 1 0 3 n \le 10^3 n≤103。
对于 60 % 60\% 60% 的数据,有 n ≤ 1 0 4 n \le 10^4 n≤104。
对于 80 % 80\% 80% 的数据,有 n ≤ 1 0 5 n \le 10^5 n≤105。
对于 100 % 100\% 100% 的数据,有 n ≤ 5 × 1 0 6 n \le 5\times 10^6 n≤5×106, p ≤ n p \le n p≤n,学生初始成绩 $ \le 100 , , ,z \le 100$。
一、考虑暴力算法:
最坏情况下时间复杂度是 O ( n p ) O(np) O(np),绝对超时。
二、差分算法
定义
定义差分数组为 b [ ] b[] b[] ,原数组为 a [ ] a[] a[]
定义 b [ i ] = a [ i ] − a [ i − 1 ] b[i] = a[i]-a[i-1] b[i]=a[i]−a[i−1]
区间修改: 时间复杂度为 O ( 1 ) O(1) O(1)
在这区间 [ l , r ] [l,r] [l,r] 中间的 b [ i ] b[i] b[i],
b [ i ] = ( a [ i ] + x ) − ( a [ i − 1 ] + x ) = a [ i ] − a [ i − 1 ] b[i] = (a[i]+x)-(a[i-1]+x) = a[i]-a[i-1] b[i]=(a[i]+x)−(a[i−1]+x)=a[i]−a[i−1] 无需改动
只有左右两端 b [ l ] b[l] b[l] 和 b [ r + 1 ] b[r+1] b[r+1] 需要改变
b [ l ] = ( a [ l ] + x ) − a [ l − 1 ] = a [ l ] − a [ l − 1 ] + x b[l] = (a[l]+x)-a[l-1] = a[l]-a[l-1]+x b[l]=(a[l]+x)−a[l−1]=a[l]−a[l−1]+x 所以 b [ l ] b[l] b[l] 需要 + = x +=x +=x
b [ r + 1 ] = a [ r + 1 ] − ( a [ r ] + x ) = a [ r + 1 ] − a [ r ] − x b[r+1] = a[r+1]-(a[r]+x) = a[r+1]-a[r]-x b[r+1]=a[r+1]−(a[r]+x)=a[r+1]−a[r]−x 所以 b [ r + 1 ] b[r+1] b[r+1]需要 − = x -=x −=x
查询:复杂度 O ( n ) O(n) O(n)
最后需要查询全班的最低分,所以我们需要用 b [ i ] b[i] b[i] 推出 a [ i ] a[i] a[i]
推导过程如下:
b [ i ] = a [ i ] − a [ i − 1 ] b[i] = a[i]-a[i-1] b[i]=a[i]−a[i−1]
a [ i ] = b [ i ] + a [ i − 1 ] a[i] = b[i]+a[i-1] a[i]=b[i]+a[i−1]
a [ i ] = b [ i ] + b [ i − 1 ] + a [ i − 2 ] a[i] = b[i]+b[i-1]+a[i-2] a[i]=b[i]+b[i−1]+a[i−2]
a [ i ] = b [ i ] + b [ i − 1 ] + b [ i − 2 ] + a [ i − 3 ] a[i] = b[i]+b[i-1]+b[i-2]+a[i-3] a[i]=b[i]+b[i−1]+b[i−2]+a[i−3]
a [ i ] = b [ i ] + b [ i − 1 ] + b [ i − 2 ] + b [ i − 3 ] + a [ i − 4 ] a[i] = b[i]+b[i-1]+b[i-2]+b[i-3]+a[i-4] a[i]=b[i]+b[i−1]+b[i−2]+b[i−3]+a[i−4]
… … …… ……
a [ i ] = b [ i ] + b [ i − 1 ] + b [ i − 2 ] + … … + b [ 1 ] a[i]=b[i]+b[i-1]+b[i-2]+……+b[1] a[i]=b[i]+b[i−1]+b[i−2]+……+b[1]
a [ i ] a[i] a[i] 即为 b [ 1 ] + b [ 2 ] + … … + b [ i ] b[1]+b[2]+……+b[i] b[1]+b[2]+……+b[i]
所以 a [ ] a[] a[] 是 b [ ] b[] b[] 的前缀和数组
利用这些,我们可以写出代码
完整AC
代码:
#include<iostream>
using namespace std;
int a[5000005], b[5000005];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n, p;
cin >> n >> p;
for(int i=1;i<=n;i++)
{
cin >> a[i];
b[i] = a[i]-a[i-1];
}
for(int i=1;i<=p;i++)
{
int x, y, z;
cin >> x >> y >> z;
b[x] += z;
b[y+1] -= z;
}
int ans = 100000000;
for(int i=1;i<=n;i++)
{
a[i] = a[i-1]+b[i];
ans = min(ans, a[i]);
}
cout << ans;
return 0;
}