题目描述
题目分析
对于此题首先想到的是暴力分析,使用前缀和,这样方便算出每一区间的大小,枚举长度和其实位置,循环计算出所有区间的和进行判断,输出答案。
非满分暴力写法:
cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
ll a[N], s[N], n, k, ans;
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
for(int i = 1; i <= n; i ++)//长度
{
for(int j = 1; j <= n; j ++)//起始位置
{
int r = j + i - 1;
if(r <= n)
{
int q = s[r] - s[j - 1];
if(q % k == 0)ans ++;
}
}
}
cout << ans;
return 0;
}
以上两重循环超时,我们把其改为一重循环
由s[r] - s[l - r] % k == 0 推出 s[r] % k == s[l - 1] % k
故我们需要固定循环右端点,确定下与此点对应相同的之前点的个数,有多少个一样的点就说明出现了多少个k倍区间,将个数加入答案即可
此点对应的值 + 1,故为cnt[s[i] % k] ++
满分代码如下:
cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
ll a[N], s[N], cnt[N], n, k, ans;
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
cnt[0] = 1;//注:s[0] % k == 0,故循环之前为0的数已经有一个
for(int i = 1; i <= n; i ++)
{
ans += cnt[s[i] % k];
cnt[s[i] % k] ++;
}
cout << ans;
return 0;
}