第八屆藍橋杯省賽 K倍區間


問題描述
  給定一個長度為N的數列,A1, A2, ... AN,如果其中一段連續的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍數,我們就稱這個區間[i, j]是K倍區間。
  你能求出數列中總共有多少個K倍區間嗎?
輸入格式
  第一行包含兩個整數N和K。(1 <= N, K <= 100000)
  以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)
輸出格式
  輸出一個整數,代表K倍區間的數目。
樣例輸入
5 2
1
2
3
4
5
樣例輸出
6
數據規模和約定
  峰值內存消耗(含虛擬機) < 256M
  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 }

 

 
 如有不當之處歡迎指出!
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM