【YBTOJ】合法序列
题目大意:
给你一个长度为 \(n\) 的正整数序列,如果一个连续的子序列,子序列的和能够被 \(k\) 整除,那么就视此子序列合法,求原序列包括多少个合法的连续子序列?
正文:
如果一段区间要合法,那么就要满足这个条件:
\[\sum_{i=l}^{r}a_i\equiv 0\pmod{k}
\]
先考虑暴力。直接枚举,\(O(n^3)\)。
优化这个暴力,我们一般可以使用前缀和,\(O(n^2)\)。
利用前缀和那么条件就变成了:
\[\begin{aligned}\text{sum}_r-\text{sum}_{l-1}&\equiv 0&\pmod{k}\\
\text{sum}_r&\equiv \text{sum}_{l-1}&\pmod{k}
\end{aligned}\]
也就是说,我们可以先求前缀和,再枚举余数,只要有前缀和模 \(k\) 余数的个数大于二的(即能匹配到的)就用排列组合求出它的价值,也就是 \(\frac{t\times(t-1)}{2}\) 其中 \(t\) 表示前缀和模 \(k\) 余数的个数。
代码:
int main() {
for (scanf ("%d", &t); t--; ) {
scanf ("%d%d", &k, &n);
memset (sum, 0, sizeof sum);
memset (bucket, 0, sizeof bucket);
for (int i = 1; i <= n; i++) {
scanf ("%lld", &sum[i]);
sum[i] += sum[i - 1];
bucket[sum[i] % k]++;
}
ll ans = 0;
++ bucket[0];
for (int i = 0; i < k; i++)
if (bucket[i] >= 2)
{
ans += bucket[i] * (bucket[i] - 1) / 2;
}
printf ("%lld\n", ans);
}
return 0;
}