#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
long long countSubarrays(const vector<long long>& nums, int k) {
// A subarray size must be >= 1. If it must also be < k,
// then k must be at least 2 for any valid subarray to exist.
if (k <= 1) return 0;
unordered_map<int, int> freq;
vector<int> history;
long long ans = 0;
long long prefix_sum = 0;
// Base case: represents the "empty" prefix sum before index 0.
// Our formula groups the terms as: (Prefix_Sum - Index) % k
// For the empty prefix: Sum is 0, Index is -1.
// Key = (0 - (-1)) % k = 1 % k.
int base_key = 1 % k;
freq[base_key]++;
history.push_back(base_key);
for (int i = 0; i < nums.size(); ++i) {
prefix_sum += nums[i];
// Sliding window logic:
// The maximum valid subarray length is k - 1.
// If our current index i >= k - 1, the prefix at index (i - k + 1) in our
// history array is now too far away and must be removed from the active map.
if (i >= k - 1) {
int key_to_remove = history[i - k + 1];
freq[key_to_remove]--;
}
// Calculate the current key: (P[i] - i) % k
long long val = (prefix_sum - i) % k;
// C++ modulo on negative numbers yields a negative result.
// We wrap it securely to guarantee a positive key.
if (val < 0) {
val = (val + k) % k;
}
int current_key = val;
// If we've seen this key in our active sliding window, it forms a valid subarray
ans += freq[current_key];
// Record the current key in the map and history for future iterations
freq[current_key]++;
history.push_back(current_key);
}
return ans;
}
int main() {
vector<pair<vector<long long>, int>> test_cases = {
{{-2, 1}, 3},
{{1, 1, 1}, 3},
{{5, 10, 15}, 1},
{{4, 4, 4}, 4},
{{1000000001, 1000000001}, 5}
};
for (int i = 0; i < test_cases.size(); ++i) {
long long result = countSubarrays(test_cases[i].first, test_cases[i].second);
cout << "Case " << i + 1 << " Answer: " << result <<endl;
}
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8dW5vcmRlcmVkX21hcD4KCnVzaW5nIG5hbWVzcGFjZSBzdGQ7Cgpsb25nIGxvbmcgY291bnRTdWJhcnJheXMoY29uc3QgdmVjdG9yPGxvbmcgbG9uZz4mIG51bXMsIGludCBrKSB7CiAgICAvLyBBIHN1YmFycmF5IHNpemUgbXVzdCBiZSA+PSAxLiBJZiBpdCBtdXN0IGFsc28gYmUgPCBrLCAKICAgIC8vIHRoZW4gayBtdXN0IGJlIGF0IGxlYXN0IDIgZm9yIGFueSB2YWxpZCBzdWJhcnJheSB0byBleGlzdC4KICAgIGlmIChrIDw9IDEpIHJldHVybiAwOwoKICAgIHVub3JkZXJlZF9tYXA8aW50LCBpbnQ+IGZyZXE7CiAgICB2ZWN0b3I8aW50PiBoaXN0b3J5OyAKICAgIAogICAgbG9uZyBsb25nIGFucyA9IDA7CiAgICBsb25nIGxvbmcgcHJlZml4X3N1bSA9IDA7CgogICAgLy8gQmFzZSBjYXNlOiByZXByZXNlbnRzIHRoZSAiZW1wdHkiIHByZWZpeCBzdW0gYmVmb3JlIGluZGV4IDAuCiAgICAvLyBPdXIgZm9ybXVsYSBncm91cHMgdGhlIHRlcm1zIGFzOiAoUHJlZml4X1N1bSAtIEluZGV4KSAlIGsKICAgIC8vIEZvciB0aGUgZW1wdHkgcHJlZml4OiBTdW0gaXMgMCwgSW5kZXggaXMgLTEuCiAgICAvLyBLZXkgPSAoMCAtICgtMSkpICUgayA9IDEgJSBrLgogICAgaW50IGJhc2Vfa2V5ID0gMSAlIGs7CiAgICBmcmVxW2Jhc2Vfa2V5XSsrOwogICAgaGlzdG9yeS5wdXNoX2JhY2soYmFzZV9rZXkpOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbnVtcy5zaXplKCk7ICsraSkgewogICAgICAgIHByZWZpeF9zdW0gKz0gbnVtc1tpXTsKCiAgICAgICAgLy8gU2xpZGluZyB3aW5kb3cgbG9naWM6IAogICAgICAgIC8vIFRoZSBtYXhpbXVtIHZhbGlkIHN1YmFycmF5IGxlbmd0aCBpcyBrIC0gMS4gCiAgICAgICAgLy8gSWYgb3VyIGN1cnJlbnQgaW5kZXggaSA+PSBrIC0gMSwgdGhlIHByZWZpeCBhdCBpbmRleCAoaSAtIGsgKyAxKSBpbiBvdXIgCiAgICAgICAgLy8gaGlzdG9yeSBhcnJheSBpcyBub3cgdG9vIGZhciBhd2F5IGFuZCBtdXN0IGJlIHJlbW92ZWQgZnJvbSB0aGUgYWN0aXZlIG1hcC4KICAgICAgICBpZiAoaSA+PSBrIC0gMSkgewogICAgICAgICAgICBpbnQga2V5X3RvX3JlbW92ZSA9IGhpc3RvcnlbaSAtIGsgKyAxXTsKICAgICAgICAgICAgZnJlcVtrZXlfdG9fcmVtb3ZlXS0tOwogICAgICAgIH0KCiAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBjdXJyZW50IGtleTogKFBbaV0gLSBpKSAlIGsKICAgICAgICBsb25nIGxvbmcgdmFsID0gKHByZWZpeF9zdW0gLSBpKSAlIGs7CiAgICAgICAgCiAgICAgICAgLy8gQysrIG1vZHVsbyBvbiBuZWdhdGl2ZSBudW1iZXJzIHlpZWxkcyBhIG5lZ2F0aXZlIHJlc3VsdC4KICAgICAgICAvLyBXZSB3cmFwIGl0IHNlY3VyZWx5IHRvIGd1YXJhbnRlZSBhIHBvc2l0aXZlIGtleS4KICAgICAgICBpZiAodmFsIDwgMCkgewogICAgICAgICAgICB2YWwgPSAodmFsICsgaykgJSBrOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpbnQgY3VycmVudF9rZXkgPSB2YWw7CgogICAgICAgIC8vIElmIHdlJ3ZlIHNlZW4gdGhpcyBrZXkgaW4gb3VyIGFjdGl2ZSBzbGlkaW5nIHdpbmRvdywgaXQgZm9ybXMgYSB2YWxpZCBzdWJhcnJheQogICAgICAgIGFucyArPSBmcmVxW2N1cnJlbnRfa2V5XTsKCiAgICAgICAgLy8gUmVjb3JkIHRoZSBjdXJyZW50IGtleSBpbiB0aGUgbWFwIGFuZCBoaXN0b3J5IGZvciBmdXR1cmUgaXRlcmF0aW9ucwogICAgICAgIGZyZXFbY3VycmVudF9rZXldKys7CiAgICAgICAgaGlzdG9yeS5wdXNoX2JhY2soY3VycmVudF9rZXkpOwogICAgfQoKICAgIHJldHVybiBhbnM7Cn0KaW50IG1haW4oKSB7CiAgICB2ZWN0b3I8cGFpcjx2ZWN0b3I8bG9uZyBsb25nPiwgaW50Pj4gdGVzdF9jYXNlcyA9IHsKICAgICAgICB7ey0yLCAxfSwgM30sCiAgICAgICAge3sxLCAxLCAxfSwgM30sCiAgICAgICAge3s1LCAxMCwgMTV9LCAxfSwKICAgICAgICB7ezQsIDQsIDR9LCA0fSwKICAgICAgICB7ezEwMDAwMDAwMDEsIDEwMDAwMDAwMDF9LCA1fQogICAgfTsKCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHRlc3RfY2FzZXMuc2l6ZSgpOyArK2kpIHsKICAgICAgICBsb25nIGxvbmcgcmVzdWx0ID0gY291bnRTdWJhcnJheXModGVzdF9jYXNlc1tpXS5maXJzdCwgdGVzdF9jYXNlc1tpXS5zZWNvbmQpOwogICAgICAgIGNvdXQgPDwgIkNhc2UgIiA8PCBpICsgMSA8PCAiIEFuc3dlcjogIiA8PCByZXN1bHQgPDxlbmRsOwogICAgfQoKICAgIHJldHVybiAwOwp9