题目传送门 \color{orangered}\text{题目传送门} 题目传送门
题意
有一个长度为 n n n 的数列,数列中第 i i i 个数被记为 a i a_i ai ( 1 ≤ i ≤ n 1≤i≤n 1≤i≤n )。
给定一个 k k k ,请按照 i = 1 , 2 , . . . , n − k + 1 i=1,2,...,n-k+1 i=1,2,...,n−k+1 的顺序计算 a i + a i + 1 + . . . + a i + k − 1 a_i+a_{i+1}+...+a_{i+k-1} ai+ai+1+...+ai+k−1 的结果并输出。
分析
这道题最直观的做法是直接按题目模拟,用双重循环来做,主要代码见下:
llrd(n);llrd(k);
for(int i=1;i<=n;i++) llrd(a[i]);
for(int i=1;i<=n-k+1;i++)
{
ll ans=0;
for(int j=i;j<=i+k-1;j++) ans+=a[j];
llwt(ans);
}
可是我们发现数据范围是 1 ≤ K ≤ N ≤ 5 × 1 0 5 1\le K \le N \le 5\times 10^5 1≤K≤N≤5×105,所以双重循环会超时,不能用双重循环来做。
正解:前缀和做法。
不知道前缀和的同学可以看一下这篇文章。
我们用 s u m i sum_i sumi 来表示从第 1 1 1 项到第 i i i 项的和,所以第 a a a 项到第 b b b 项的和就是 s u m b − s u m a − 1 sum_b-sum_{a-1} sumb−suma−1。
枚举每个 i i i,输出 s u m i + k − 1 − s u m i − 1 sum_{i+k-1}-sum_{i-1} sumi+k−1−sumi−1 即可,记得换行。
完整代码见下。
代码
#include<bits/stdc++.h>
#define rd(n) scanf("%d",&n)
#define llrd(n) scanf("%lld",&n)
#define wt(n) printf("%d",n)
#define llwt(n) printf("%lld\n",n)
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;
ll n,k;
ll a[500100],sum[500100];
int main()
{
llrd(n);llrd(k);
for(int i=1;i<=n;i++)
{
llrd(a[i]);
sum[i]=sum[i-1]+a[i];
}
for(int i=1;i<=n-k+1;i++) llwt(sum[i+k-1]-sum[i-1]);
return 0;
}