|
Последний раз редактировалось wrest 28.10.2025, 02:30, всего редактировалось 2 раз(а).
В общем, дописал я функцию. Немного длинно получилось, правда. Основной цикл работает весьма быстро. На вход даём номер замечательного числа, на выходе получаем вектор кратности цифр в виде [цифра1,количество],...
- comb(n)={
- /* функция возвращает вектор кратностей цифр n-го замечательного числа */
- /* входной контроль */
- if(n<1,error("n must be positive, got n=",n));
- /* нерегулярные случаи */
- if(n<10,return([[n,1]]));
- if(n==10,return([[1,1],[0,0]])); /* тут по неубыванию не выходит */
-
- /* начало основного вычисления */
- my(len=floor((sqrt(8*sqrt(n-2)+1)-1)/2)); /* вычисляем длину числа -- количество цифр в нём */
- my(npos=n-len^2*(len+1)^2/4-1); /* вычисляем относительную позицию числа где единица -- начало ряда чисел нашей длины */
-
- /* Определяем фиксированные цифры */
- my(fixed_digits = vector(7));
- fixed_digits[1] = [[2, 1]]; /* тип 1 */
- fixed_digits[2] = [[2, 1], [6, 1]]; /* тип 2 */
- fixed_digits[3] = [[3, 1]]; /* тип 3 */
- fixed_digits[4] = [[4, 1]]; /* тип 4 */
- fixed_digits[5] = []; /* тип 5 */
- fixed_digits[6] = [[6, 1]]; /* тип 6 */
-
- /* Вычисляем размеры диапазонов для каждого из 6 типов*/
- my(type_len=vector(6,i,len-#fixed_digits[i])); /* длина сочетания равна длине числа минус количество фиксированных цифр */
- my(type_range=vector(6,i,(type_len[i]+1)*(type_len[i]+2)*(type_len[i]+3)/6)); /* тетраэдральные числа */
- my(type_finish=vector(6,i,sum(j=1,i,type_range[j]))); /* концы диапазонов шаблонов */
-
- /* Определяем тип числа */
- my(type_num, type_pos);
- if(npos <= type_finish[2],
- type_num = 2; type_pos = npos;
- , npos <= type_finish[3],
- type_num = 3; type_pos = npos - type_finish[2];
- , npos <= type_finish[4],
- type_num = 4; type_pos = npos - type_finish[3];
- , npos <= type_finish[6],
- type_num = 6; type_pos = npos - type_finish[4];
- ,
- error("npos too big: ", npos)
- );
-
- /* Обрабатываем составные типы 12 и 56, которые идут вперемешку */
-
- if(type_num == 2 || type_num == 6,
- my(m = floor((3*type_pos)^(1/3))); /* примерно куб, иначе пришлось бы по формуле Кардано */
- if(m*(m+1)*(m+2)/3 >= type_pos, m--); /* если не попали, корректируемся */
-
- my(Sm = m*(m+1)*(m+2)/6);
- my(offset = type_pos - 2*Sm);
- my(L = (m+1)*(m+2)/2);
-
- my(subtype = if(offset <= L, 1, 0));
- type_pos = Sm + if(subtype == 1, offset, offset - L);
-
- /* Преобразуем в окончательный тип 1 2 или 5 6*/
- type_num=type_num-subtype;
- );
-
- /* начинаем вычислять кратности цифр 5789 */
- my(elts=[5,7,8,9]); /* вектор элементов для генерации их сочетания */
- my(v_mult=vector(#elts,i,vector(2))); /* заготавливаем вектор кратностей цифр 5789 */
-
- /*
- Вычисляем вектор кратностей для сочетания с повторениями
- номер type_pos, из #elts элементов по type_len[type_num], в лексикографическом порядке
- по неубывающим последовательностям (т.е. сначала все минимальные элементы).
- */
- my(n=#elts);
- my(m = n + type_len[type_num] - 1, t = n - 1, total = binomial(m, t));
-
- /* приводим type_pos к 0-based */
- type_pos = type_pos - 1;
-
- /* инвертируем позицию, чтобы порядок стал лексикографическим по неубыванию --- */
- type_pos = total - 1 - type_pos;
-
- /* выбираем позиции перегородок (1..m) */
- my(seps = vector(t), prev = 0, cnt, s);
- /* основной цикл, хорошо работает до длин 10^8 */
- for (j = 1, t,
- for (s = prev + 1, m - (t - j),
- cnt = binomial(m - s, t - j);
- if (type_pos >= cnt,
- type_pos = type_pos-cnt;
- next;
- ,
- seps[j] = s;
- prev = s;
- break;
- );
- );
- );
-
- /* переводим позиции перегородок в кратности (число звёзд между ними) */
-
- for(i=1,n,v_mult[i][1]=elts[i]);
- v_mult[1][2] = seps[1] - 1;
- for (j = 2, t, v_mult[j][2] = seps[j] - seps[j-1] - 1);
- v_mult[n][2] = m - seps[t];
- /* добавляем фиксированные цифры и сортируем результат по неубыванию */
- v_mult = vecsort(concat(v_mult, fixed_digits[type_num])); /* в принципе, готовои ещё чуть: */
-
- /* удаляем нулевые кратности */
- my(res=[]);
- for(i=1,#v_mult,if(v_mult[i][2]>0,res=concat(res,[v_mult[i]])));
-
- return(res);
- }
Запускаем: Код: ? comb(2025) %2 = [[8, 1], [9, 7]] ? comb(10^10) time = 2 ms. %3 = [[5, 213], [6, 1], [7, 81], [8, 122], [9, 29]] ? comb(10^20) time = 78 ms. %4 = [[5, 24252], [7, 30922], [8, 45059], [9, 41187]] ? comb(10^25) time = 1,248 ms. %5 = [[3, 1], [5, 1160494], [7, 139287], [8, 765244], [9, 449840]] ? comb(20^25) time = 1min, 48,938 ms. %6 = [[3, 1], [5, 1420700], [7, 16335714], [8, 136434330], [9, 37213898]] ? 2 миллисекунды на вычисление замечательного числа номер 
|