Модераторы: Alx, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [Pascal] Сумма цифр всех целых чисел, заочная олимпиада по информатике 
:(
    Опции темы
KasMP
Дата 15.10.2006, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

Репутация: 2
Всего: 30



Решаю заочную олимпиаду по информатике. Упор делается на неординарность решения, нестандартность алгоритма и т.п..
Одна из задач:
Цитата
Пусть дано целое число M. Найти сумму цифр всех целых чисел от 1 до M. Т.е. если M=13, тогда программа выдаст: 1+2+3+4+5+6+7+8+9+1+0+1+1+1+2+1+3=55.

В паскале есть оператор выделения кол-ва десятков, сотен и т.п. или оператор выделения цифры, стоящей на первой, второй, третьей и т.д. позиции? smile 
smile  smile 
PM MAIL   Вверх
Alexeis
Дата 15.10.2006, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 3
Всего: 459



Цитата(KasMP @  15.10.2006,  11:39 Найти цитируемый пост)
В паскале есть оператор выделения кол-ва десятков, сотен и т.п. или оператор выделения цифры, стоящей на первой, второй, третьей и т.д. позиции?

Нет нужно делить число на 10 (целочисленое деление div 10) и брать остаток от целочисленого дления (mod 10), остаток дает очередную цифру. Затем операция повторяется уже над числом разделенным на 10.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
KasMP
Дата 15.10.2006, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

Репутация: 2
Всего: 30



alexeis1, спасибо. smile

Таким образом, у меня получилось следующее:

Примечания:
m - число M ("... найти сумму всех целых чисел от 1 до M ...);
s - сумма всех целых чисел от 1 до M;
r - результат целочисленного деления на 10 одного из чисел, принадлежащих [1; M];
o - остаток от целочисленного деления на 10 одного из чисел, принадлежащих [1; M]
- переменная для [1; M].

Операторы вывода опускаю. smile 
Код
var i, m, o, r, s: integer;
label 1;

begin
s:=0;
readln (m);
for i:=m downto 1 do begin
    1:
    r:=i div(10); o:=i mod(10);
    if r>=10 then begin
        s:=s+o;
        goto 1;
        end
    else s:=s+r+o;
    end;
end.

Только мне кажется, что такой алгоритм не может претендовать на неординарность, экзотичность и т.д.. smile  smile Как вы думаете? smile 
Если у вас есть какие-то свои алгоритмы и мысли, то, пожалуйста, поделитесь. smile Ваше мнение важно и интересно. smile 
PM MAIL   Вверх
Sartorius
Дата 15.10.2006, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1568
Регистрация: 18.7.2006
Где: Ivory tower

Репутация: нет
Всего: 37



 Есть такая мысль - держать текущее число в качестве массива - array[1..10] of byte. Самому сделать операцию прибавления единицы(это очетнь просто). Тогда подсчет сведется к простомму суммированию элементов массива. 
PM MAIL ICQ   Вверх
Alexeis
Дата 15.10.2006, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 3
Всего: 459



Цитата(Sartorius @  15.10.2006,  14:45 Найти цитируемый пост)
держать текущее число в качестве массива - array[1..10] of byte

Но тогда все равно прийдется проделывать ту же самую операцию для полученя цифр числа.

KasMP, это и правду самый класический, пример, но проблема в том, что числа то хранятся в двоичной системе счисления, а нужна десятичная. Эта операция делает ни что иное как обычный перевод из двоичной в десятичную систему счисления.
 Как альтернатива использование двоично-десятичного представления чисел (того которое используется в калькуляторах). При этом каждая 10 - чная цифра записывается ввиде 4 бит байта. В этом случае получение цифры сводится к простейшей операции сдвига на 4 разряда. Но паскаль не поддерживатет работу с такими числами, тут надо лезть в ассемблер.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
KasMP
Дата 15.10.2006, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

Репутация: 2
Всего: 30



Цитата(Sartorius @  15.10.2006,  14:45 Найти цитируемый пост)
держать текущее число в качестве массива - array[1..10] of byte

Видимо, я чего-то не знаю, но мне всегда казалось, что держать одно число в массиве из 10 элементов невозможно. Ведь число одно, а элементов 10 (т.е., конечно, можно оставить 9 ячеек массива пустыми и выбрать какую-то одну (так тогда имхо проще просто использовать переменную, а не целый массив), но как можно одно число описать через 10 элементов???).
Или для описания десятичного числа через числа типа byte необходимо несколько чисел (цифр?) типа byte?
(извините за тафтологию, но более понятно сказать не получается).
Или как? smile 
Цитата(Sartorius @  15.10.2006,  14:45 Найти цитируемый пост)
Самому сделать операцию прибавления единицы(это очетнь просто).

Ты бы не мог привести пример для наглядности? smile 
_______________________________________________

Цитата(alexeis1 @  15.10.2006,  15:32 Найти цитируемый пост)
Но паскаль не поддерживатет работу с такими числами, тут надо лезть в ассемблер. 

Эм... А от паскаля до ассемблера очень далеко? Или они, так сказать, братья по крови? smile  smile 
PM MAIL   Вверх
Sartorius
Дата 15.10.2006, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1568
Регистрация: 18.7.2006
Где: Ivory tower

Репутация: нет
Всего: 37



Извините если че не так... давно на паскале не писал
Код

var num : array[0..9] of byte;
procedure MyInc;
var i : integer;
begin
 inc(num[0]);
 for i := 0 to  9 do
 begin
  if(num[i] > 9)
  begin
    num[i] := 0;
    inc(num[i+1]);
  end;
 end;
end;
begin
  num[0] := 1;
  {теперь увеличиваем число M-1 раз и суммируем цифры}
end.

PM MAIL ICQ   Вверх
maxim1000
Дата 15.10.2006, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 2
Всего: 110



Цитата(alexeis1 @  15.10.2006,  14:32 Найти цитируемый пост)
Но паскаль не поддерживатет работу с такими числами, тут надо лезть в ассемблер.

паскаль поддерживает работу с массивами/структурами и позволяет их обрабатывать с помощью функций
этого вполне достаточно, чтобы не задумываться об ассемблере в данном случае

касательно задачи в целом:
1. если число меньше 10 - всё понятно, n*(n-1)/2
2. если число больше 9, но меньше 100, можно попробовать так:
разбиваем весь отрезок 1..N на отрезки с одинаковыми старшими цифрами и считаем их отдельно
получится куча полных отрезков из 10 элементов (например, 20,21,22,23,24,25,26,27,28,29) и один неполный - там, где находится заданная граница
подсчитать сумму цифр в полном отрезке легко: считаем сумму старших цифр (т.е просто умножаем её на 10) и сумму младших (т.е. просто записываем 9*(9-1)/2)
в неполном отрезке особо можно и не заморачиваться - считаем простым способом

ну а дальше можно развивать этотподход на трёх- и более значные числа...


--------------------
qqq
PM WWW   Вверх
Alexeis
Дата 15.10.2006, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 3
Всего: 459



Цитата(KasMP @  15.10.2006,  16:02 Найти цитируемый пост)
Эм... А от паскаля до ассемблера очень далеко? Или они, так сказать, братья по крови?

Оч. далеко  smile  Лучше делать как сказал maxim1000 - это намного логичнее и красивее  smile .


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
KasMP
Дата 16.10.2006, 11:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

Репутация: 2
Всего: 30



Цитата(Sartorius @  15.10.2006,  16:10 Найти цитируемый пост)
Извините если че не так... давно на паскале не писал

Спасибо за пример. smile 
Но, к сожалению, пока мне не хватает знаний/умений/опыта для понимания твоей мысли (не знаю, что такое inc; плохо понимаю тип byte и т.д.).
(маленькая опечаточка есть: после if всегда следует then)
__________________________________________________________

Цитата(maxim1000 @  15.10.2006,  16:17 Найти цитируемый пост)
1. если число меньше 10 - всё понятно, n*(n-1)/2
2. если число больше 9, но меньше 100, можно попробовать так:
разбиваем весь отрезок 1..N на отрезки с одинаковыми старшими цифрами и считаем их отдельно
получится куча полных отрезков из 10 элементов (например, 20,21,22,23,24,25,26,27,28,29) и один неполный - там, где находится заданная граница
подсчитать сумму цифр в полном отрезке легко: считаем сумму старших цифр (т.е просто умножаем её на 10) и сумму младших (т.е. просто записываем 9*(9-1)/2)
в неполном отрезке особо можно и не заморачиваться - считаем простым способом

ну а дальше можно развивать этотподход на трёх- и более значные числа... 

maxim100, спасибо за участие. smile 
Похожая мысль меня посещала... И я была вынуждена отказаться от нее по след.причинам:
а) числом N теоретически вполне может оказаться 10 в очень большой степени. Прописать варианты для промежутков 10<=n<100, 100<=n<1000, 1000<=n<10000 и т.д. не представляется возможным, т.к множество чисел бесконечно (или в некотором смысле конечно? я где-то слышала, что максимальное число, которым может оперировать паскаль при типе integer немного больше 30000)
(не знаю, может, можно как-то автоматизировать этот процесс: выделить степень числа (если число 12453 (т.е. 10000+2453), то его степень - 4), обозначить эту степень чем-нибудь и потом до тех пор, пока степень не станет равна 1 (или нулю?), выполнять некоторые операции; но пока не знаю, надо еще подумать...);
б) необходимо делить программу на 2 части: на, как выразился maxim100, полные отрезки и на остаток;
в) необходимо создавать механизм, определяющий, когда пора завершать считывание полных отрезком и приниматься за остаток.

Хотя, с точки зрения неординарности этот подход, наверно, смотрится очень даже неплохо. smile 
PM MAIL   Вверх
Alexeis
Дата 16.10.2006, 12:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 3
Всего: 459



Цитата(KasMP @  16.10.2006,  11:47 Найти цитируемый пост)
(не знаю, что такое inc; плохо понимаю тип byte и т.д.).
(маленькая опечаточка есть: после if всегда следует then)


inc(i); тоже что и i := i + 1; только быстрее работает
byte - это тот же integer но беззнаковый и более маленький - значения (0..255)

А на счет if - это проблема всех кто пишет на C++ (там этого нет)


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
maxim1000
Дата 16.10.2006, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 2
Всего: 110



касательно диапазонов: если число не выходит за пределы 16 бит, достаточно рассмотреть 5 степеней (32 бита - не более 10), дальше - арифметика длинных чисел

с точки зрения автоматизации всего этого мысли тут такие:
вводим число An - сумма цифр всех чисел от 0 до (10^n)-1
теперь берём число x и начинаем его обрабатывать:
---1.для начала разбиваем его на старшую часть (старшая цифра и нули) - y и младшую часть (все цифры кроме старшей) - z
для x=3456 y=3000, z=456
---2.считаем сумму цифр чисел от 0 до y-1
ну точнее не считаем, а используем знание чисел An:
для y=3000
s[0..2999]=s[0..999]+s[1000..1999]+s[2000..2999]=A3+1*1000+A3+2*1000+A3
для общего случая получается An*d+10^n*(0+1+2+...+d-1)=An*d+10^n*d*(d-1)/2
d - старшая цифра
n - её порядок
(тут надо с бумажкой посидеть и проверить - мог напутать)
---3.считаем сумму цифр от y до x (=y+z)
s[3000..3456]=456*3+s[0..456]
ну или для общего случая:
s[y..y+z]=z*d+s[0..z]
ну а s[0..z] считаем рекурсивно этой же функцией, а его порядок уже на 1 меньше
(екурсивный вызов будет в конце, так что можно потом будет без проблем переделать в цикл, если надо)

подсчёт An - тоже рекурсивный:
An=S[0..(10^n)-1]=s[0..1*(10^(n-1))-1]+s[1*(10^(n-1))..2*(10^(n-1))-1]+...=
(1+2+3+4+5+6+7+8+9)*10^(n-1)+10*A[n-1]
т.е. можно прямо перед подсчётом вычислить массив нужных An (количество посмотреть по порядку числа), и использовать его потом
его размер логарифмический, что часто приемлимо
в принципе, если сильно надо, можно изменить порядок рекурсии и считать, начиная с младших частей, тогда можно будет обойтись даже без массива, но это уже дальнейшая оптимизация...


--------------------
qqq
PM WWW   Вверх
KasMP
Дата 17.10.2006, 18:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

Репутация: 2
Всего: 30



Хорошие новости: сегодня узнала, что можно ограничить число M удобным мне множеством [1; N]. smile 
В таком случае, ничего лучше, чем деление числа на полные отрезки и остаток smile придумать нельзя (по крайней мере, пока я не придумала).
Код
var    d, i, m, o, r, s: integer;


begin

writeln ('Введите m, принадлежащее [1; 100).');
readln (m);


r:=m div(10); {кол-во десятков, кол-во полных отрезков}
o:=m-r*10; {остаток}

for i:=0 to 9 do d:=d+i; {сумма цифр [0;9]}
for i:=1 to r do s:=s+i; {сумма цифр второй позиции}
for i:=1 to o do s:=s+1; {сумма цифр первой позиции, принадлежащих остатку}

s:=s+r*d; {прибавляем сумму цифр первой позиции всех полных отрезков}


writeln ('Сумма цифр числа ', m, ' равна: ', s, '.');

readln;
end.

Но потом, когда доделаю до конца олимпиаду и смогу спокойно, в размеренном ритме, никуда не торопясь, думать, то обязательно попробую  "автоматизировать" процесс считывания степени т.д. (уж очень интересно попробовать smile )
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Интересные и занимательные задачи по программированию | Следующая тема »


 




[ Время генерации скрипта: 0.0893 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.