253 lines
7.5 KiB
Markdown
253 lines
7.5 KiB
Markdown
![]() |
---
|
|||
|
id: 5900f3a91000cf542c50febc
|
|||
|
title: 'Завдання 61: Циклічні фігурні числа'
|
|||
|
challengeType: 5
|
|||
|
forumTopicId: 302173
|
|||
|
dashedName: problem-61-cyclical-figurate-numbers
|
|||
|
---
|
|||
|
|
|||
|
# --description--
|
|||
|
|
|||
|
Трикутні, квадратні, п'ятикутні, шестикутні, семикутні і восьмикутні числа є фігурними (багатокутними) числами і визначаються за такими формулами:
|
|||
|
|
|||
|
| Тип числа | Формула | Послідовність |
|
|||
|
| ----------- | ----------------------------- | --------------------- |
|
|||
|
| Трикутне | $P_3(n) = \frac{n(n+1)}{2}$ | 1, 3, 6, 10, 15, ... |
|
|||
|
| Квадратне | $P_4(n) = n^2$ | 1, 4, 9, 16, 25, ... |
|
|||
|
| П'ятикутне | $P_5(n) = \frac{n(3n−1)}2$ | 1, 5, 12, 22, 35, ... |
|
|||
|
| Шестикутне | $P_6(n) = n(2n−1)$ | 1, 6, 15, 28, 45, ... |
|
|||
|
| Семикутне | $P_7(n) = \frac{n(5n−3)}{2}$ | 1, 7, 18, 34, 55, ... |
|
|||
|
| Восьмикутне | $P_8(n) = n(3n−2)$ | 1, 8, 21, 40, 65, ... |
|
|||
|
|
|||
|
Впорядкована множина з трьох 4-значних чисел: 8128, 2882, 8281 має три цікаві властивості.
|
|||
|
|
|||
|
1. Множина циклічна, оскільки дві останні цифри кожного числа є першими двома цифрами наступного числа (включаючи останнє та перше число).
|
|||
|
2. Кожен тип багатокутника: трикутний ($P_3(127) = 8128$), квадратний ($P_4(91) = 8281$), і п'ятикутний ($P_5(44) = 2882$), представлений іншим числом в даній множині.
|
|||
|
3. Це єдина множина 4-цифрових чисел з цією властивістю.
|
|||
|
|
|||
|
Знайдіть суму всіх чисел у впорядкованих множинах з `n` циклічних 4-значних чисел, в яких кожен з типів багатокутника від $P_3$ до $P_{n + 2}$ представлений іншим числом цієї множини.
|
|||
|
|
|||
|
# --hints--
|
|||
|
|
|||
|
`cyclicalFigurateNums(3)` має повернути число.
|
|||
|
|
|||
|
```js
|
|||
|
assert(typeof cyclicalFigurateNums(3) === 'number');
|
|||
|
```
|
|||
|
|
|||
|
`cyclicalFigurateNums(3)` має повернути `19291`.
|
|||
|
|
|||
|
```js
|
|||
|
assert.strictEqual(cyclicalFigurateNums(3), 19291);
|
|||
|
```
|
|||
|
|
|||
|
`cyclicalFigurateNums(4)` має повернути `28684`.
|
|||
|
|
|||
|
```js
|
|||
|
assert.strictEqual(cyclicalFigurateNums(4), 28684);
|
|||
|
```
|
|||
|
|
|||
|
`cyclicalFigurateNums(5)` має повернути `76255`.
|
|||
|
|
|||
|
```js
|
|||
|
assert.strictEqual(cyclicalFigurateNums(5), 76255);
|
|||
|
```
|
|||
|
|
|||
|
`cyclicalFigurateNums(6)` має повернути `28684`.
|
|||
|
|
|||
|
```js
|
|||
|
assert.strictEqual(cyclicalFigurateNums(6), 28684);
|
|||
|
```
|
|||
|
|
|||
|
# --seed--
|
|||
|
|
|||
|
## --seed-contents--
|
|||
|
|
|||
|
```js
|
|||
|
function cyclicalFigurateNums(n) {
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
cyclicalFigurateNums(3);
|
|||
|
```
|
|||
|
|
|||
|
# --solutions--
|
|||
|
|
|||
|
```js
|
|||
|
function cyclicalFigurateNums(n) {
|
|||
|
function getChains(chain, n, numberTypes, numsExcludingLastNeededType) {
|
|||
|
if (chain.length === n) {
|
|||
|
return [chain];
|
|||
|
}
|
|||
|
|
|||
|
const nextNumbers = getNextNumbersInChain(
|
|||
|
chain[chain.length - 1],
|
|||
|
numsExcludingLastNeededType
|
|||
|
);
|
|||
|
|
|||
|
const chains = [];
|
|||
|
for (let j = 0; j < nextNumbers.length; j++) {
|
|||
|
const nextNumber = nextNumbers[j];
|
|||
|
if (chain.indexOf(nextNumber) === -1) {
|
|||
|
const nextChain = [...chain, nextNumber];
|
|||
|
chains.push(
|
|||
|
...getChains(nextChain, n, numberTypes, numsExcludingLastNeededType)
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
return chains;
|
|||
|
}
|
|||
|
|
|||
|
function getNextNumbersInChain(num, numsExcludingLastNeededType) {
|
|||
|
const results = [];
|
|||
|
const beginning = num % 100;
|
|||
|
numsExcludingLastNeededType.forEach(number => {
|
|||
|
if (Math.floor(number / 100) === beginning) {
|
|||
|
results.push(number);
|
|||
|
}
|
|||
|
});
|
|||
|
return results;
|
|||
|
}
|
|||
|
|
|||
|
function fillNumberTypes(n, numberTypes, numsExcludingLastNeededType) {
|
|||
|
const [, lastTypeCheck, lastTypeArr] = numberTypes[n - 1];
|
|||
|
|
|||
|
for (let i = 1000; i <= 9999; i++) {
|
|||
|
for (let j = 0; j < n - 1; j++) {
|
|||
|
const [, typeCheck, typeArr] = numberTypes[j];
|
|||
|
if (typeCheck(i)) {
|
|||
|
typeArr.push(i);
|
|||
|
numsExcludingLastNeededType.add(i);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (lastTypeCheck(i)) {
|
|||
|
lastTypeArr.push(i);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isCyclicalChain(chain, n, numberTypes) {
|
|||
|
const numberTypesInChain = getNumberTypesInChain(chain, numberTypes);
|
|||
|
|
|||
|
if (!isChainAllowed(numberTypesInChain, n)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
const isChainCyclic =
|
|||
|
Math.floor(chain[0] / 100) === chain[chain.length - 1] % 100;
|
|||
|
return isChainCyclic;
|
|||
|
}
|
|||
|
|
|||
|
function getNumberTypesInChain(chain, numberTypes) {
|
|||
|
const numbersInChain = {};
|
|||
|
for (let i = 0; i < numberTypes.length; i++) {
|
|||
|
const numberTypeName = numberTypes[i][0];
|
|||
|
numbersInChain[numberTypeName] = [];
|
|||
|
}
|
|||
|
|
|||
|
for (let i = 0; i < chain.length; i++) {
|
|||
|
for (let j = 0; j < n; j++) {
|
|||
|
const [typeName, , typeNumbers] = numberTypes[j];
|
|||
|
const typeNumbersInChain = numbersInChain[typeName];
|
|||
|
if (typeNumbers.indexOf(chain[i]) !== -1) {
|
|||
|
typeNumbersInChain.push(chain[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return numbersInChain;
|
|||
|
}
|
|||
|
|
|||
|
function isChainAllowed(numberTypesInChain, n) {
|
|||
|
for (let i = 0; i < n; i++) {
|
|||
|
const typeName = numberTypes[i][0];
|
|||
|
const isNumberWithTypeInChain = numberTypesInChain[typeName].length > 0;
|
|||
|
if (!isNumberWithTypeInChain) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
for (let j = i + 1; j < n; j++) {
|
|||
|
const otherTypeName = numberTypes[j][0];
|
|||
|
if (
|
|||
|
isNumberRepeatedAsOnlyNumberInTwoTypes(
|
|||
|
numberTypesInChain[typeName],
|
|||
|
numberTypesInChain[otherTypeName]
|
|||
|
)
|
|||
|
) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
function isNumberRepeatedAsOnlyNumberInTwoTypes(
|
|||
|
typeNumbers,
|
|||
|
otherTypeNumbers
|
|||
|
) {
|
|||
|
return (
|
|||
|
typeNumbers.length === 1 &&
|
|||
|
otherTypeNumbers.length === 1 &&
|
|||
|
typeNumbers[0] === otherTypeNumbers[0]
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
function isTriangle(num) {
|
|||
|
return ((8 * num + 1) ** 0.5 - 1) % 2 === 0;
|
|||
|
}
|
|||
|
|
|||
|
function isSquare(num) {
|
|||
|
return num ** 0.5 === parseInt(num ** 0.5, 10);
|
|||
|
}
|
|||
|
|
|||
|
function isPentagonal(num) {
|
|||
|
return ((24 * num + 1) ** 0.5 + 1) % 6 === 0;
|
|||
|
}
|
|||
|
|
|||
|
function isHexagonal(num) {
|
|||
|
return ((8 * num + 1) ** 0.5 + 1) % 4 === 0;
|
|||
|
}
|
|||
|
|
|||
|
function isHeptagonal(num) {
|
|||
|
return ((40 * num + 9) ** 0.5 + 3) % 10 === 0;
|
|||
|
}
|
|||
|
|
|||
|
function isOctagonal(num) {
|
|||
|
return ((3 * num + 1) ** 0.5 + 1) % 3 === 0;
|
|||
|
}
|
|||
|
|
|||
|
const numberTypes = [
|
|||
|
['triangle', isTriangle, []],
|
|||
|
['square', isSquare, []],
|
|||
|
['pentagonal', isPentagonal, []],
|
|||
|
['hexagonal', isHexagonal, []],
|
|||
|
['heptagonal', isHeptagonal, []],
|
|||
|
['octagonal', isOctagonal, []]
|
|||
|
];
|
|||
|
const numsExcludingLastNeededType = new Set();
|
|||
|
fillNumberTypes(n, numberTypes, numsExcludingLastNeededType);
|
|||
|
|
|||
|
const nNumberChains = [];
|
|||
|
const [, , lastType] = numberTypes[n - 1];
|
|||
|
for (let i = 0; i < lastType.length; i++) {
|
|||
|
const startOfChain = lastType[i];
|
|||
|
nNumberChains.push(
|
|||
|
...getChains([startOfChain], n, numberTypes, numsExcludingLastNeededType)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
const cyclicalChains = nNumberChains.filter(chain =>
|
|||
|
isCyclicalChain(chain, n, numberTypes)
|
|||
|
);
|
|||
|
|
|||
|
let sum = 0;
|
|||
|
for (let i = 0; i < cyclicalChains.length; i++) {
|
|||
|
for (let j = 0; j < cyclicalChains[0].length; j++) {
|
|||
|
sum += cyclicalChains[i][j];
|
|||
|
}
|
|||
|
}
|
|||
|
return sum;
|
|||
|
}
|
|||
|
```
|