Нехай d_1, d_2, ..., d_n — вхідні числа. Розглянемо всі їх часткові суми
Оскільки часткових сум рівно , то серед усіх значень s_i~mod~n обов’язково знайдуться або два однакових, або хоча б одне значення, рівне нулю.
Якщо для деяких індексів a - 1 < b виконується
то сума d_a + ... + d_b ділиться на .
Отже, послідовність чисел d_a, d_{a + 1}, ..., d_b є шуканою.
Якщо ж існує таке , що s_i~mod~n = 0, то шуканою буде послідовність d_1, d_2, ..., d_i.
Приклад
Розглянемо наведений приклад. Обчислимо всі часткові суми:
Шуканих наборів є декілька. Наприклад:
оскільки s_1 = s_3, то d_2 + d_3 = 5 ділиться на .
оскільки s_1 = s_5, то d_2 + d_3 + d_4 + d_5 = 10 ділиться на .
оскільки s_3 = s_5, то d_4 + d_5 = 5 ділиться на .
оскільки s_4 = 0, то d_1 + d_2 + d_3 + d_4 = 10 ділиться на .
Реалізація алгоритму
Вхідні числа будемо зберігати в масиві . Масив використовуємо для фіксації часткових сум: якщо s = d_1 + ... + d_i, то присвоїмо r[s] = i.
#define MAX 10100
int d[MAX], r[MAX];Шуканим набором чисел, сума яких ділиться на , будуть d_a, d_{a+1}, ..., d_b. Виводимо їхню кількість b - a + 1, а потім самі числа — по одному на кожному рядку.
void print(int a, int b)
{
printf("%d\n",b - a + 1);
for(int i = a; i <= b; i++)
printf("%d\n",d[i]);
}Основна частина програми. Ініціалізуємо масив значенням і встановлюємо r[0] = 0, щоб врахувати випадок, коли сума перших чисел ділиться на .
memset(r,-1,sizeof(r)); r[0] = 0;Читаємо кількість чисел .
scanf("%d",&n);Часткові суми за модулем обчислюємо в змінній .
sum = 0;
for (i = 1; i <= n; i++)
{
scanf("%d", &d[i]);
sum = (sum + d[i]) % n;Якщо часткова сума зустрілась повторно, то виводимо шуканий набір чисел:
if (r[sum] != -1)
{
print(r[sum] + 1, i);
break;
}зберігає перший індекс , на якому зустрілася часткова сума d_1 + ... + d_i з залишком при діленні на .
else r[sum] = i;
}