問題描述
給定一個長度為N的數列,A1, A2, ... AN,如果其中一段連續的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍數,我們就稱這個區間[i, j]是K倍區間。
你能求出數列中總共有多少個K倍區間嗎?
你能求出數列中總共有多少個K倍區間嗎?
輸入格式
第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)
輸出格式
輸出一個整數,代表K倍區間的數目。
樣例輸入
5 2
1
2
3
4
5
1
2
3
4
5
樣例輸出
6
數據規模和約定
峰值內存消耗(含虛擬機) < 256M
CPU消耗 < 2000ms
CPU消耗 < 2000ms
思路
這題暴力復雜度為$O(n^2)$,無法通過所有數據。
我提供兩種思路來解決這個問題:
首先求出數組的前綴和並對k取余。前綴和是數組的前j個元素的和$\sum\limits_{i = 1}^j {a[i]}$。假設經過求余得到的數組為$\{ {y_1},{y_2},...,{y_n}\}$,比如樣例中的$y$數組為{1,1,0,0,1}。
1.對於數組$y$,如果${y_i} = {y_j}(i < j)$,那么$\sum\limits_{t = i + 1}^j {{t_i}}$必定是$k$的倍數。設$c_x$表示數組$y$等於$x$的元素個數,但是要特別注意等於0的情況,要讓$c_0+1$!!
答案就是$\sum\limits_{i = 0}^{k - 1} {{c_i} \times ({c_i} - 1)/2}$。
2.在計算數組$y$同時,第$i$個元素能和前面的元素構成$c_{y_i}-1$個k倍區間,這樣一直計算下去就是答案。
總而言之,這兩種思路都是基於余數相同區間和必為k的倍數來實現的。
AC代碼
1 #include <stdio.h> 2 #include <string.h> 3 const int maxn = 100000 + 5; 4 typedef long long LL; 5 int a[maxn], cnt[maxn]; 6 int n, k; 7 int main() { 8 while(scanf("%d%d", &n, &k) == 2) { 9 int sum = 0; 10 LL ans = 0; 11 memset(cnt, 0, sizeof(cnt)); 12 for(int i = 0; i < n; i++) { 13 scanf("%d", &a[i]); 14 sum = (sum + a[i] % k) % k; 15 cnt[sum]++; 16 } 17 cnt[0]++; 18 for(int i = 0; i < k; i++) { 19 ans += (1LL * cnt[i] * (cnt[i]-1)) / 2; 20 } 21 printf("%lld\n", ans); 22 } 23 return 0; 24 }
如有不當之處歡迎指出!