很容易想到前缀和,但在找区间的时候就会超时,要利用取模运算的性质
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p ) % p
(a * b) % p = (a % p * b % p) % p
(a ^ b) % p = ((a % p) ^ b) % p
在前缀和数组里,存放取模后的值,因为是前缀和是数组,根据取模性质,模后值相同的,相减肯定是k的倍数,值相同的随机组合,模后值为0的个体也计入结果
样例模拟
![]()
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
ll a[N];//存储数
ll s[N];//前缀和数组
ll s1[N];//记录模后值的个数
int n,k;
ll sum = 0;//区间总数
int main()
{
cin >> n >> k;
for(int i = 1; i<= n; i++)
{
cin >> a[i];
s[i] = s[i-1]+a[i];
s1[s[i]%k]++;//模后值的个数
}
for(int i = 0;i<n;i++)
{
sum+=s1[i]*(s1[i]-1)/2;//模后值相同的任取2个
}
cout << sum+s1[0] << endl;//加上本身就是k倍区间的
return 0;
}