Я добавляю это как второй ответ, так как он находится на другом языке (теперь C) и имеет более прямой подход. Я сохраняю оригинальный ответ, так как следующий код почти необъяснимо без него. Я объединил две свои функции в одну, чтобы сократить накладные расходы на функции. Кроме того, чтобы быть на 100% уверенным, что он отвечает на исходный вопрос, я использовал петли из этого вопроса дословно. В функции драйвера я явно показываю, что вывод правильный для N = 4, а затем стресс-тест для N = 10000 (всего 100 000 000 проходов через внутренний цикл). У меня нет никакого формального кода времени, но на моей машине требуется около 1 секунды, чтобы проверить и проверить эти 100 миллионов случаев. Мой код предполагает 32-разрядный int
. Изменение в long
при необходимости:
#include <stdio.h>
#include <math.h>
void from_index(int n, int index, int *i, int *j);
int main(void){
int N;
int ri,rj; //recovered i,j
N = 4;
int index = 0;
for (int i = 0; i < N; ++i)
for (int j = 0; j < N-i; ++j){
from_index(N,index,&ri,&rj);
printf("i = %d, j = %d, index = %d, ",i,j,index);
printf("recovered i = %d, recovered j = %d\n",ri,rj);
index++;
}
//stress test:
N = 10000;
index = 0;
for (int i = 0; i < N; ++i)
for (int j = 0; j < N-i; ++j){
from_index(N,index,&ri,&rj);
if(i != ri || j != rj){
printf("Don't post buggy code to Stack Overflow!\n");
printf("(i,j) = (%d,%d) but recovered indices are (%d,%d)\n",i,j,ri,rj);
return 0;
}
index++;
}
printf("\nAll %d tests passed!\n",N*N);
return 0;
}
void from_index(int n, int index, int *i, int *j){
double d;
d = 4*n*(n+1) - 7 - 8 * index;
*i = floor((-1 + sqrt(d))/2);
*j = *i * (*i + 1)/2;
*j = n*(n+1)/2 - 1 - index - *j;
*j = *i - *j;
*i = n - *i - 1;
}
Выход:
i = 0, j = 0, index = 0, recovered i = 0, recovered j = 0
i = 0, j = 1, index = 1, recovered i = 0, recovered j = 1
i = 0, j = 2, index = 2, recovered i = 0, recovered j = 2
i = 0, j = 3, index = 3, recovered i = 0, recovered j = 3
i = 1, j = 0, index = 4, recovered i = 1, recovered j = 0
i = 1, j = 1, index = 5, recovered i = 1, recovered j = 1
i = 1, j = 2, index = 6, recovered i = 1, recovered j = 2
i = 2, j = 0, index = 7, recovered i = 2, recovered j = 0
i = 2, j = 1, index = 8, recovered i = 2, recovered j = 1
i = 3, j = 0, index = 9, recovered i = 3, recovered j = 0
All 100000000 tests passed!
вы имеете в виду, как частное и остаток? –
@JohnColeman Это немного сложнее, чем из-за переменной верхней границы внутреннего цикла. Но ответ «да, это возможно». В худшем случае вы можете воспроизвести две петли и сломаться, когда достигнете значения индекса: p Но вы можете, вероятно, сделать это в постоянное время, решая некоторые квадратичные уравнения (уравнения). – cobarzan
Я пропустил это 'i'. Вероятно, необходимо использовать тот факт, что 1 + 2 + 3 + ... + n = n (n + 1)/2. Кажется, нужно немного алгебры вместо прямой теории чисел. Я голосую вопрос как интересный и не совсем тривиальный. –