跳到主要内容
关系图

同余定理

若 amod  k=bmod  ka\mod k = b \mod k 则 ∣a−b∣mod  k=0|a - b| \mod k = 0

例题​

链接: P8649 [蓝桥杯 2017 省 B] k 倍区间

[蓝桥杯 2017 省 B] k 倍区间

Tip

本题的前置题目: 523. 连续的子数组和 前缀和 + 维护左、枚举右

题目描述​

给定一个长度为 NN 的数列,A1,A2,⋯ANA_1,A_2, \cdots A_N,如果其中一段连续的子序列 Ai,Ai+1,⋯Aj(i≤j)A_i,A_{i+1}, \cdots A_j(i \le j) 之和是 KK 的倍数,我们就称这个区间 [i,j][i,j] 是 KK 倍区间。

你能求出数列中总共有多少个 KK 倍区间吗?

输入格式​

第一行包含两个整数 NN 和 KK (1≤N,K≤105)(1 \le N,K \le 10^5)。

以下 NN 行每行包含一个整数 AiA_i (1≤Ai≤105)(1 \le A_i \le 10^5)。

输出格式​

输出一个整数,代表 KK 倍区间的数目。

样例 #1​

样例输入 #1​

5 2
1
2
3
4
5

样例输出 #1​

6

提示​

时限 2 秒, 256M。蓝桥杯 2017 年第八届

代码

wa​

前缀和, 后朴素遍历 O(n2)O(n^2)

#include <cstdio>
#include <vector>

using namespace std;

int main() {
int n, k;
scanf("%d %d", &n, &k);

vector<int> arr(n);
vector<int> sumArr(n + 1);
for (int i = 0; i < n; ++i) {
scanf("%d", &arr[i]);
sumArr[i + 1] = arr[i] + sumArr[i];
}

int res = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if ((sumArr[j] - sumArr[i - 1]) % k == 0)
++res;
}
}

printf("%d\n", res);

return 0;
}
C++

正解​

由同余定理得: 余数为 ii 的有 arr[i]arr[i] 个, 那么他们可以组成区间数量为 Carr[i]2C^2_{arr[i]} (无需考虑边算边更新, 因为我们可以看成区间都是相同的元素(组合数学))

  • 为什么前缀和不做差得 [i,j][i, j] 区间, 而是直接可以使用 [0,i][0, i] 区间 ?!

    • ok, 摊牌了, 世界未解之谜tmd
  • 为什么需要arr[0] = 1;预处理?

    • 如果不预处理, 对于输入 [1, 1, 1], k = 2
    • 那么显然有arr[0] = 1, arr[1] = 2, 然后res = 2才是正解
    • Carr[1]2=(arr[1])(arr[1]−1)2=1C^2_{arr[1]}=\frac{(arr[1])(arr[1] - 1)}{2}=1 没问题
    • 但是因为 Carr[0]2=(arr[0])(arr[0]−1)2=1×(1−1)2=0C^2_{arr[0]}=\frac{(arr[0])(arr[0] - 1)}{2}=\frac{1 \times (1-1)}{2}=0 所以需要进行初始化: arr[0] = 1

不开long long见祖宗

#include <cstdio>
#include <vector>

using namespace std;

int main() {
int n, k;
scanf("%d %d", &n, &k);

vector<long long> arr(n);
arr[0] = 1;
long long sum = 0;
for (int i = 0; i < n; ++i) {
long long j;
scanf("%lld", &j);
sum = (sum + j) % k;
++arr[sum];
}

long long res = 0;
for (int i = 0; i < k; ++i) {
res += (arr[i] * (arr[i] - 1)) / 2;
}

printf("%lld\n", res);

return 0;
}
C++
请作者喝奶茶:
Alipay IconQR Code
Wechat IconQR Code
本文遵循 CC CC 4.0 BY-SA 版权协议, 转载请标明出处
Loading Comments...