題目描述:
給定乙個長度為 n 的數列,a1,a2,…an,如果其中一段連續的子串行 ai,ai+1,…aj 之和是 k 的倍數,我們就稱這個區間 [i,j] 是 k 倍區間。
你能求出數列中總共有多少個 k 倍區間嗎?
輸入格式
第一行包含兩個整數 n 和 k。
以下 n 行每行包含乙個整數 ai。
輸出格式
輸出乙個整數,代表 k 倍區間的數目。
資料範圍
1≤n,k≤100000,
1≤ai≤100000
輸入樣例:
5 212
345輸出樣例:
解題思路:
1.最簡單的方法,採用暴力列舉,三層迴圈
for
(int r =
1; r <= n; r++
)for
(int l =
1; l <= n; l++
) 判斷是否可整除k
}
這個方法最簡單,最容易想到,但是時間複雜度在 n 的三次方,因為資料量是100000,所以肯定不過。
2.公升級版1
優化最裡面一層迴圈,將其優化,可以另外開闢乙個陣列sum,存前n項和,這樣,裡面可以變成
sum[r]-sum[l-1]
for
(int r =
1; r <= n; r++
)for
(int l =
1; l <= n; l++
)}
這樣子,較為容易想到,時間複雜度在n的二次方,資料量太大,依舊過不掉,因為在十萬次,所以平方次複雜度仍過高
3.極度優化
因為:(sum[r]-sum[l])%k==0)
所以:只要sum[r]%k == sum[l]%k
,則這個區間是k被區間,也就是說,只要兩個模k的餘數相同,即兩數區間為k倍區間,所以,可以開闢陣列,存餘數相同的個數
ac**:
#include
using
namespace std;
long
long sum[
100005];
//存放字首和
long
long re[
100005];
//存放模k的餘數
intmain()
long
long res =0;
//res存放幾個k倍區間
re[0]
=1;//我們的sum[0]預設是0,所以re[0] = 1,這裡可能很多人不能理解,因為當餘數是0的時候,其實那乙個數字也可以的,
/* 例如,樣例輸入
5 21 2 3 4 5
這時候 sum陣列是: 1 3 6 10 15
取模的時候是:1 1 0 0 1
但是這個時候注意:當餘數0這個數字剛放進去的時候,切記,這個數字也是單個其實就是k的倍數了,所以這個re[0] = 1,為的就是把這個單個數字計算進去,
可能會有人說,那如果餘數為0的,是不是多算了
你們可以試試
例如:1 2
1這個時候sum是:1
取模是:1
那麼計算的時候在下面迴圈的時候不會有re[0]加進去
這就是為什麼re[0]=1;
*/for(
int i =
1; i <= n; i++
)printf
("%lld"
, res)
;//最後輸出結果,ac
return0;
}
第八屆藍橋杯省賽C B組 K倍區間
給定乙個長度為 n 的數列,a1,a2,an,如果其中一段連續的子串行 ai,ai 1,aj 之和是 k 的倍數,我們就稱這個區間 i,j 是 k 倍區間。你能求出數列中總共有多少個 k 倍區間嗎?輸入格式 第一行包含兩個整數 n 和 k。以下 n 行每行包含乙個整數 ai。輸出格式 輸出乙個整數,...
第八屆藍橋杯省賽C B組 K倍區間
演算法標籤 字首和 題目描述 給定乙個長度為 n 的數列,a1,a2,an,如果其中一段連續的子串行 ai,ai 1,aj 之和是 k 的倍數,我們就稱這個區間 i,j 是 k 倍區間。你能求出數列中總共有多少個 k 倍區間嗎?輸入格式 第一行包含兩個整數 n 和 k。以下 n 行每行包含乙個整數 ...
第八屆藍橋杯C B組 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 ...