Çoxluğu tap#5621

Çoxluğu tap (Həll təhlili)

Tutaq ki, d_1, d_2, ..., d_n — giriş ədədləridir. Bu ədədlərin hamısının qismən cəmlərini nəzərdən keçirək

s_i = d_1 + ... + d_i

Qismən cəmlərin sayı məhz olduğuna görə, bütün s_i~mod~n qiymətləri arasında ya iki bərabər, ya da ən az biri sıfıra bərabər olan bir dəyər mütləq tapılacaq.

Əgər bəzi indekslər üçün a - 1 < b şərti ödənirsə

s_{a-1}~mod~n = s_b~mod~n,

onda d_a + ... + d_b cəmi -ə bölünür.

Nəticədə, d_a, d_{a + 1}, ..., d_b ədədlər ardıcıllığı axtarılan ardıcıllıqdır.

Əgər elədə bir mövcuddursa ki, s_i~mod~n = 0, onda axtarılan ardıcıllıq d_1, d_2, ..., d_i olacaqdır.

Nümunə

Gətirilmiş nümunəni nəzərdən keçirək. Bütün qismən cəmləri hesablayacağıq:

Axtarılan dəstlərdən bir neçə var. Məsələn:

Alqoritmin həyata keçirilməsi

Giriş ədədlərini massivində saxlayacağıq. Qismən cəmləri fiksasiya etmək üçün massivindən istifadə edəcəyik: əgər s = d_1 + ... + d_i, onda r[s] = i əmrini verəcəyik.

#define MAX 10100
int d[MAX], r[MAX];

Cəmləri -ə bölünən axtarılan ədədlər dəsti d_a, d_{a+1}, ..., d_b olacaq. Onların sayını b - a + 1 çıxış edəcəyik, sonra isə ədədlərin özlərini hər sətirdə birini olmaqla verəcəyik.

void print(int a, int b)
{
  printf("%d\n",b - a + 1);
  for(int i = a; i <= b; i++)
    printf("%d\n",d[i]);
}

Proqramın əsas hissəsi. massivini ilə başla və ilk ədədlərinin cəmi -ə bölünəndə r[0] = 0 ayarla.

memset(r,-1,sizeof(r)); r[0] = 0;

Ədədlərin sayını oxuyuruq.

scanf("%d",&n);

Qismən cəmləri -ə modal olaraq dəyişənində hesablayırıq.

sum = 0;
for (i = 1; i <= n; i++)
{
  scanf("%d", &d[i]);
  sum = (sum + d[i]) % n;

Əgər qismən cəm təkrarlanarsa, axtarılan ədədlər dəstini çıxış edirik:

d_{r[sum] + 1}, d_{r[sum] + 2}, ..., d_i
  if (r[sum] != -1)
  {
    print(r[sum] + 1, i);
    break;
  }

ilk indeksini saxlayır, burada d_1 + ... + d_i qismən cəmi -ə bölündükdə qalan olur.

  else r[sum] = i;
}