【YBTOJ】合法序列
阿新 • • 發佈:2020-12-17
題目大意:
給你一個長度為 \(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; }