先贴个题目:
以及原题链接: 1230. K倍区间 - AcWing题库https://www.acwing.com/problem/content/1232/
讲讲思路,这题其实可以暴力如果数据不够强的话,但很显然以acwing的数据是不行的,因为暴力差不多就是n方复杂度,1e10的计算量只会收获TLE,所以考虑优化。这里我们可以自己找规律也可以利用裴蜀定理(详见裴蜀定理_百度百科 (baidu.com))。这里简单概括,如果(a-b)%k=0,那么a%k=b%k。接下来就可以搞定一个O(n)的算法了。
#include <iostream>
using namespace std;
int main()
{
int n, k ;
long long sum = 0;
cin >> n >> k;
long long *a = new long long[n + 10];
long *b = new long[n + 10];
cin >> a[1];
for (int i = 2; i < n + 1; ++i){
int num;
cin >> num;
a[i] = a[i - 1] + num;
}
b[0] = 1;
for (int i = 1; i < n + 1; ++i){
sum += b[a[i] % k];
b[a[i] % k]++;
}
cout << sum;
}
a数组用来存前缀和,b数组用来存到当前位置时每种a%k的余数的节点已经有几个,然后遍历,每次遇到就加上可能的节点选取(即节点数),然后让节点数加一,最后输出总和就好。
这里需要注意:因为本身如果可以被除尽,那么自身也是一个k倍区间,所以要把b[0]设为1.
b[0] = 1;
(昨晚太晚了今早起来写题解)
by————2024.2.3刷题记录