題意:問有多少段的和能被k整除
這個題跟我入隊考試的題非常的像。
首先他問我們某一段的和是不是乙個k的倍數,那麼一段和我們很自然的就聯想到字首和了。而且我們知道,如果對每乙個字首和都進行%k處理,那麼就一定會使得某些數是0(假設這個數的位置是i),那麼就說明從1到i的所有的數的和都是k的倍數。那麼我們也會得到有的和並不是0,而是1~(k - 1)中的數。但是不妨礙裡面有相同的數。
假設 s[i] % k = x,那麼我們有取餘的定義可知:
s [i
]/k=
n⋯xk
∗n+x
=s[i
]s[i] / k = n \cdots x \\ k * n + x = s[i]
s[i]/k
=n⋯x
k∗n+
x=s[
i]那麼假設還有乙個數s[j]的取餘結果也是x,同理
k ∗m
+x=s
[j
]k * m + x = s[j]
k∗m+x=
s[j]
兩式相減得:
k ∗n
−k∗m
=s[i
]−s[
j]k∗
(n−m
)=s[
i]−s
[j
]k*n - k*m=s[i]-s[j]\\ k*(n-m) = s[i]-s[j]
k∗n−k∗
m=s[
i]−s
[j]k
∗(n−
m)=s
[i]−
s[j]
那麼就可以得到:
( s[
i]−s
[j])
/k=(
n−m)
⋯0
(s[i]-s[j]) / k = (n - m) \cdots 0
(s[i]−
s[j]
)/k=
(n−m
)⋯0即:
( s[
i]−s
[j])
%k=0
(s[i]-s[j]) \% k = 0
(s[i]−
s[j]
)%k=
0那麼我們就能得到一下結論:
如果某個餘數在出現過之後在它後面再次出現過,那麼 [ i , j ]這個區間就可以是個k倍區間。
所以說,假設乙個餘數出現過 m 次,那麼同時包含這個餘數的k倍區間的個數就是 (m - 1) * m / 2次(因為出現的第一次無法與前面組成k倍區間)
假設出現了5次當0為餘數的時候,就是它出現的次數就是(m + 1) * m / 2(餘數是0 的時候,第一次出現的那個位置也可以組成乙個k倍區間)1 2 3 4 5
1 21 3
2 31 4
2 43 4
1 52 5
3 54 5
每個位置與前面的組成答案,就是 1 + 2 + 3 + 4 + …(n - 2) * (n -1) = (n - 1) * n / 2
#include
#include
#define ll long long
using
namespace std;
int n;
ll a[
100000+10
];int k;
ll s[
100000+10
];//看資料範圍我們知道,a[i]最大100000,你們到最後s[i]最大到100000 * 100000 = 10^10超出int
vector wei[
100000+10
];//存第幾位出現的,其實這裡只存出現的個數就行;讀者可以自行更改一下
intmain()
ll x = wei[0]
.size()
; ll cnt = x *
(x +1)
/2;for
(int i =
1; i <= k; i++
) cout << cnt;
return0;
}
其實這種做法跟y總的思路差不多, 藍橋杯 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 10...
藍橋杯 K倍區間
時間限制 2.0s 記憶體限制 256.0mb 給定乙個長度為n的數列,a1,a2,an,如果其中一段連續的子串行ai,ai 1,aj i j 之和是k的倍數,我們就稱這個區間 i,j 是k倍區間。你能求出數列中總共有多少個k倍區間嗎?輸入格式 第一行包含兩個整數n和k。1 n,k 100000 以...
藍橋杯 k倍區間
暴力模擬 雙迴圈肯定超時了,需要找到數字間的規律進行優化 includeusing namespace std typedef long long ll define maxn 100005 sum r sum l 1 就是區間 l,r 的和。區間 l,r 的和是k的倍數即 sum r sum l ...