Ortada Görüş#11431

Ortada Görüş (Həll təhlili)

Giriş massivini iki bərabər hissəyə bölün: t_1, t_2, ..., t_{n/2} və t_{n/2+1}, t_{n/2+2}, ..., t_n. Birinci hissəni massivində, ikinci hissəni isə massivində saxlayırıq.

Əvvəlcə ardıcıllığı üçün problemi həll edək. Onun bütün mümkün altməsələlərini seçək (onların sayı 2^{20} -dən çox olmayacaq). Hər altməsələ üçün onun elementlər cəmini hesablayırıq və hər belə cəm üçün dəyəri artırılır. Məlumat quruluşu kimi üçün unordered_map istifadə edilə bilər. Beləliklə, massivindən cəmi elementi olan altməsələni seçmənin sayı olacaq.

Sonra massivinin bütün altməsələlərini götürək. Götürək ki, həmin altməsələlərdən birinin elementlərinin cəmidir. Əgər bu altməsələni massivindən elementi s - sum olan bütün altməsələlərlə birləşdirərək, orijinal massivdən cəmi olan altməsələ alınırsa.

Nümunə

İkinci nümunəni nəzərdən keçirək. Giriş ardıcıllığını iki hissəyə bölək:

a = \{1, 3, 2\} dəstinin bütün altməsələlərini yoxlayaq:

\{1\}: sum = 1, m[1]++;

\{1, 2\}: sum = 3, m[3]++;

\{3\}: sum = 3, m[3]++;

\{3, 2\}: sum = 5, m[5]++;

\{2\}: sum = 2, m[2]++;

\{1, 3, 2\}: sum = 6, m[6]++;

\{1, 3\}: sum = 4, m[4]++;

\{\}: sum = 0, m[0]++;

məlumat quruluşu hissə dəstələrdən sonra aşağıdakı qiymətlərə malik olacaq:

İndi b = \{2, 1, 4\} dəstinin bütün altməsələlərini yoxlayaq. Bu nümunədə tələb olunan cəm s = 7 bərabərdir. Hər cəm üçün, , altməsələsinə uyğun olan, cavablara m[s - sum] dəyərini əlavə edəcəyik.

Axtarılan cəm 1 + 1 + 2 + 1 + 1 + 1 + 1 + 0 = 8, bu da cavabdır.

Alqoritmin implementasiyası

İş məlumat strukturlarını elan edək.

vector<int> a, b;
unordered_map<long long, long long> m;

Giriş məlumatlarını oxuyuruq. Ardıcılın ilk yarısını massivinə, ikinci yarısını isə massivinə daxil edirik.

scanf("%d %d", &n, &s);
a.resize(n / 2);
for (i = 0; i < n / 2; i++)
  scanf("%d", &a[i]);

b.resize(n - n / 2);
for (i = n / 2; i < n; i++)
  scanf("%d", &b[i - n / 2]);

ardıcıllığının bütün altməchullarını yoxlayırıq və onların elementlərinin cəmini hesablayırıq. unordered_map quruluşunda, bu altməchullar arasında hər bir cəmin neçə dəfə tapıldığını saxlayırıq. Əgər cari altmëxullanın cəmidir, dəyərini artırırıq.

for (i = 0; i < (1 << a.size()); i++)
{
  sum = 0;

dəyişəni cari altməxullunun bit maskasını ehtiva edir. Onun elementlərinin cəmi dəyişənində hesablanır.

      for (j = 0; j < a.size(); j++)
        if (i & (1 << j)) sum += a[j];

Tapılmış hər cəm üçün dəyərini artırırıq.

  m[sum]++;
}

Orijinal massivin elementlərindən cəmi əldə etməyin yollarını dəyişənində sayırıq.

res = 0;

ardıcıllığının bütün altməchullarını yoxlayırıq.

for (i = 0; i < (1 << b.size()); i++)
{
  sum = 0;

dəyişəni cari altməxullunun bit maskasını ehtiva edir. Bu altməxullunun elementlərinin cəmi dəyişənində hesablanır.

  for (j = 0; j < b.size(); j++)
    if (i & (1 << j)) sum += b[j];

Əgər dəstinin cəm elementləri olan cari altməchuları, s - sum cəm elementləri olan bütün altməchuları ilə birləşdirilsə, cəmi olan bir altməchulaq əldə edilir.

  if (m.count(s - sum) > 0) res += m[s - sum];
}

Cavabı çıxışa yazırıq.

printf("%lld\n", res);