İki massiv#11725

İki massiv (Həll təhlili)

Birləşdirilmiş ardıcıllığı nəzərdən keçirək:

a_1, a_2, ..., a_m, b_m, b_{m - 1}, ..., b_1

Onun uzunluğu -ə bərabərdir. Məsələnin şərtindən aydın olur ki, bu ardıcıllıq:

Deməli, məsələ aşağıdakı artmayan ardıcıllıqların sayını hesablamağa çevrilir:

1 \le x_1 \le x_2 \le ... \le x_{2m} \le n

Değişkenlərin dəyişməsini həyata keçirək:

y_1 = x_1 - 1, \\ y_2 = x_2 - x_1, \\ y_3 = x_3 - x_2, \\ ..., \\ y_{2m} = x_{2m} - x_{2m-1}, \\ y_{2m+1} = n - x_{2m}

O zaman bütün y_i \ge 0, və onların cəmi aydın olur ki

y_1 + y_2 + ... + y_{2m} + y_{2m+1} = n - 1

Beləliklə, bu problem n - 1 ədədini 2m + 1 qeyri-mənfi tam əlavələrə bölmənin sayını hesaplamaya çevrilir. Belə bölmələrdən hər birinə dəqiq bir artmayan ardıcıllıq x_1, x_2, ..., x_{2m} uyğun gəlir, buna görə də dəqiq bir cüt array uyğun gəlir.

Təkrarlı birləşmələrin klassik formuluna görə belə bölmələrin sayı C_{n+2m-1}^{2m}-ə bərabərdir (bax Eolimp məsələsi ).

Misal

Birinci testdə uyğun variant var:

Uyğun birləşdirilmiş ardıcıllıq aşağıdakı bərabərsizliyin şərtlərini ödəmiş olur:

1 \le a_1 \le a_2 \le b_2 \le b_1 \le 2

Değişkenlərin dəyişməsini həyata keçirək:

y_1 = a_1 - 1, \\ y_2 = a_2 - a_1, \\ y_3 = b_2 - a_2, \\ y_4 = b_1 - b_2, \\ y_5 = 2 - b_1

Değmək dəyişənləri cəmləyək:

y_1 + y_2 + ... + y_5 = 1, 0 \le y_i \le 1

Bu bərabərliyin həlli var. Onlardan hər birində dəqiq bir dəyişən y_i-ə -ə bərabərdir, digər bütün dəyişənlər -a bərabərdir. Bu həllərin ilkin ardıcıllıqlara uyğun nəticələrini nəzərdən keçirək:

Alqoritmin reallaşdırması

dəyişəninin bir dəyişənini və massivi təyin edək, burada dp[n][k] = C_n^k.

#define MOD 1000000007
long long dp[3001][30];

Cnk funksiyası binomial koeffisienti olan C_n^k-nin qiymətini hesablamaq üçün istifadə edilir.

long long Cnk(int n, int k)
{
  if (n == k) return 1;
  if (k == 0) return 1;
  if (dp[n][k] != -1) return dp[n][k];
  return dp[n][k] = (Cnk(n - 1, k - 1) + Cnk(n - 1, k)) % MOD;
}

Proqramın əsas hissəsi. Verilənləri oxuyuruq.

scanf("%d %d", &n, &m);

Müxtəlif -ni başlandığımız.

memset(dp, -1, sizeof(dp));

Cavab C_{n+2m-1}^{2m}-nin hesablayıb və çıxarırıq.

printf("%d\n", Cnk(n + 2 * m - 1, 2 * m));