powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничные лампочки
92 сообщений из 92, показаны все 4 страниц
Тяпничные лампочки
    #39170092
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здарова челы!

Сори за боян и олимпиаду. В смежном топике ботаны увлеклись сравнением чисел
астрономической разрядности (дай бох им всем здоровья) а мы тут будем колбасить
теплые "ламповые операции". OK! Let is go!

Задача.

http://acmp.ru/index.asp?main=task&id_task=337
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170106
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

но ведь суббота!
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170109
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В принципе решается тупым перебором, но вот уложится ли он в 2 секунды - не уверен.
Точнее, при фактических входных данных, конечно, уложится, а вот при количестве лампочек ближе к 10 9 - уже вряд ли.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170149
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Считаем от 1 до N, каждый шаг проверяем на какое количество P i делится нацело. Если нечетное "итого+1"
дальше оптимизация: разложение на простые, поиск минимального шага цикла, поиск одинаковых интервалов и т.д. и т.п.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170150
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
НОД(P) это шаг цикла НОК(P) предел цикла, дальше он повторяется.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170151
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В массиве P много повторов (100 элементов <50). Все задвоения надо просто выкинуть.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170166
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чтобы не делить, проще использовать К счетчиков каждый со своим шагом Р:
нашли минимум, посчитали кол-во счетчиков равных минимуму, нечетное - "итого+1", каждый счетчик в минимуме увеличить на Р и т.д.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170286
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока есть мысль что некоторые кратные инверсии типа 2:4 можно соптимизировать
и учесть заранее. Два на четыре это тоже самое что четыре но со "сдвигом".

Есть также мысль проверять взаимную простоту чисел.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170373
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Входные данные

nLamps = 1000000000;
nInversions = 10;
Periods = new int[]{19,2,7,13,40,23,16,1,45,9};

Результат
Time elapsed: 00:00:05.2807186
Lamps = 525373291. Press any key to continue . . .
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170380
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Биткарта?
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170392
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonБиткарта?
Точно. Забыл выкинуть лишнее.
Поправил =)

Time elapsed: 00:00:00.6150498
Lamps = 525373291. Press any key to continue . . .
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170394
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglВходные данные

nLamps = 1000000000;
nInversions = 10;
Periods = new int[]{19,2,7,13,40,23,16,1,45,9};

Результат
Time elapsed: 00:00:05.2807186
Lamps = 525373291. Press any key to continue . . .

1. Выкинь единицы. Просто добавь флаг инверсия результата. Т.е. вместо количество нечетных - кол-во четных.

2. Считай до НОК, это примерно 50 млн., дальше все повторяется. Например счетчики 4 и 5: НОК 20, внутри 20 (4,5,8,10,12,15,16, 20) 8 ламп. В миллиарде 8 * 1000000000 / 20 = 400000000. Не забудь что остаток может быть: например НОК = 30, предел 100, т.е. результат = (цикл до 30) * 3 + (цикл до 10).

3. Деление убрал?

mayton, для биткарты 16 Мб не хватит.

PS Вообще некогда, попозже, если успею - напишу. Но вроде все очень просто. Я основные детали алгоритма выше уже изложил.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170403
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Про шаг 1 наврал, надо считать без него, а потом инверсия "итого = всего - итого"
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170409
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tmayton, для биткарты 16 Мб не хватит.

PS Вообще некогда, попозже, если успею - напишу. Но вроде все очень просто. Я основные детали алгоритма выше уже изложил.
Думаю что в этом весь цимес.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170416
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, цимес имеется.

У меня на сайтике стабильно заваливается 7й тест - если биткарта, то 2с мне нехватает, если без биткарты - то завал по памяти (
Переписывать на С++ не хочу.

В общем с биткартой на данных ниже у меня
nLamps = 1000000000;
nInversions = 10;
Periods = new int[]{19,2,7,13,40,23,16,1,45,9};

Time elapsed work+count: 00:00:01.2806298
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170440
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglУ меня на сайтике стабильно заваливается 7й тест
Написал. так же 7. Wrong answer. Есть какая-то комбинация в условиях которую не учли.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170447
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglПереписывать на С++ не хочу.
на C# используй структуры (struct вместо class), будет близко по скорости к c++
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170448
Фотография tchingiz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TSiemarglПереписывать на С++ не хочу.
на C# используй структуры (struct вместо class), будет близко по скорости к c++
а есть, вообще, готовый пример, показывающий что сортировка структур идет быстрее сортировки классов? Или это религиозная догма.
Пытался както померять скорость на структурах и на классах - разницы не увидел.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170451
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TSiemarglУ меня на сайтике стабильно заваливается 7й тест
Написал. так же 7. Wrong answer. Есть какая-то комбинация в условиях которую не учли.

Например, число в данных встречается дважды.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170452
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЕсть какая-то комбинация в условиях которую не учли.
Попробуйте такое:
Код: plaintext
1.
1000000000 17
2 3 5 7 11 13 17 19 23 29 31 37 39 41 43 47 49
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170457
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovDima TЕсть какая-то комбинация в условиях которую не учли.
Попробуйте такое:
Код: plaintext
1.
1000000000 17
2 3 5 7 11 13 17 19 23 29 31 37 39 41 43 47 49

спасибо, все банально тупо
переполнение при расчете НОК, выход за разрядность
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170464
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovDima TЕсть какая-то комбинация в условиях которую не учли.
Попробуйте такое:
Код: plaintext
1.
1000000000 17
2 3 5 7 11 13 17 19 23 29 31 37 39 41 43 47 49

Переполнение убрал, но теперь "Time limit exceeded", надо еще какую-то оптимизацию дополнительную.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170466
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно попробовать окна из биткарт, как тут делал
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170515
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Все гораздо хуже. Я пока сходил за пивом, изобрел решение без биткарт, без массивов и вообще без сложностей.

Все= в 2с не укладывается этот шарп (
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170521
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TSiemarglПереписывать на С++ не хочу.
на C# используй структуры (struct вместо class), будет близко по скорости к c++
Поучи свою бабушку яичницу жарить =)

У меня уже идеальный алгоритм.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170534
Fort Knox
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Когда-то на форум.сорцы.ру их мембер albom с блеском решил эту таску.

-------- http://forum.sources.ru/index.php?showtopic=250789
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170589
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglВсе гораздо хуже. Я пока сходил за пивом, изобрел решение без биткарт, без массивов и вообще без сложностей.

Все= в 2с не укладывается этот шарп (
В результатах лучшее время 0,284 сек на С++. Получается C# тормознее в 7+ раз? Не верю.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170594
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С окнами из биткарт дошел до 10 теста. Time limit exceeded
В чистом виде биткарта не поможет, нужна еще какая-то оптимизация.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170645
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TSiemarglВсе гораздо хуже. Я пока сходил за пивом, изобрел решение без биткарт, без массивов и вообще без сложностей.

Все= в 2с не укладывается этот шарп (
В результатах лучшее время 0,284 сек на С++. Получается C# тормознее в 7+ раз? Не верю.
Потому что у меня все же перебор, а оптимальное решение - вычислительное - просто сложить пару десятков чисел, как Кнокс на форуме откопал. Но так неинтересно.

Алгоритм получился простым, может и перепишу потом на С
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170675
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ссылку пока не смотрел, хочу сам голову поломать.

ИМХУ условия поставлены так что перебором нерешаемо. Хоть на асме пиши.

Этот пример 18813721 имеет ответ ~500 млн., требует полного перебора до лярда, т.е. даже при самом оптимальном алгоритме перебора (попадание только на нужные) чтобы уложиться в 2 сек. на проце в 3 ГГц надо на проверку тратить не более 6 тактов процессора, что очень мало.

Самый быстрый способ: заполнить биткарту и то дольше 2 сек будет. Даже без ограничения по памяти.

Надо изобретать какую-то алгоритмическую хитрость. Знать бы хоть в какую сторону ее искать.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170722
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TСсылку пока не смотрел, хочу сам голову поломать.

ИМХУ условия поставлены так что перебором нерешаемо. Хоть на асме пиши.

Этот пример 18813721 имеет ответ ~500 млн., требует полного перебора до лярда, т.е. даже при самом оптимальном алгоритме перебора (попадание только на нужные) чтобы уложиться в 2 сек. на проце в 3 ГГц надо на проверку тратить не более 6 тактов процессора, что очень мало.

Самый быстрый способ: заполнить биткарту и то дольше 2 сек будет. Даже без ограничения по памяти.

Надо изобретать какую-то алгоритмическую хитрость. Знать бы хоть в какую сторону ее искать.

давно бы уже код показал )
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170739
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovдавно бы уже код показал )
Стыдно показывать, накидал по-быстрому, сейчас причешу вариант с биткартой окнами (он самый быстрый) и выложу.
Может кому пригодится для проверки или как заготовка.

У тебя нет мыслей по оптимизации без перебора? ИМХУ в эту сторону надо копать.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170752
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, мысли есть, конечно, но они очевидные все. Вдруг ты забыл что-нибудь.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170757
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Исходник с++. Окно биткарты
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
#include <fstream>
#include <iostream>
using namespace std;

#include <stdio.h>
#include <time.h>

// Размер окна биткарты в байтах
#define BM_SIZE 8192 // 8 Kb

int main(int argc, char**argv)
{
	// Считывание задания
	ifstream in("input.txt");
	int N, K;
	in >> N >> K;
	bool P[51] = { 0 };
	int cnt = 0; // кол-во полезных счетчиков
	for (int i = 0; i < K; i++) {
		int v;
		in >> v;
		P[v] = !P[v];
		if (P[v]) {
			cnt++;
		} else {
			cnt--;
		}
	}
	if (P[1]) cnt--; // единицы не считаем

	int res = 0;
	if (cnt) {
		int* steps = (int*)calloc(cnt, sizeof(int)); // шаги счетчиков
		int* values = (int*)calloc(cnt, sizeof(int)); // значения счетчиков
		for (int i = 2, j = 0; i <= 50; i++) {
			if (P[i]) {
				steps[j] = i;
				values[j] = i;
				j++;
#ifdef _DEBUG
				cout << i << " ";
#endif
			}
		}
		// Для подсчета единичных бит в байте
		int bit_cnt[256] = { 0 };
		for (int i = 0; i < 256; i++) {
			int n = i;
			while (n != 0) {
				bit_cnt[i]++;
				n = n & (n - 1);
			}
		}
		// Биткарта
		unsigned char* bm = (unsigned char*)calloc(BM_SIZE, 1);
		int next = 0;
		while (next <= N) {
			int start = next;
			next += BM_SIZE * 8;
			if (next > N) next = N + 1;
			// Заполнение окна биткарты
			for (int i = 0; i < cnt; i++) {
				int lim = next - start; // конец биткарты
				int v = values[i] - start, s = steps[i];
				for (; v < lim; v += s) { 
					bm[v >> 3] ^= (1 << (v & 7));
				}
				values[i] = v + start;
			}
			// считывание результата
			for (int i = 0; i < BM_SIZE; i++) {
				res += bit_cnt[bm[i]];
				bm[i] = 0;
			}
		}
	}
	// Инверсия если была единица
	if (P[1]) res = N - res;
	// Вывод результата
	ofstream out("output.txt");
	out << res << endl;
	out.close();
	cout << endl << "time " << clock() << endl;
	cout << "Result " << res << endl;
	return 0;
}



Забывать тут нечего, примитивный перебор - самый быстрый из всех переборов. Из оптимизации только контроль задвоений счетчиков.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170765
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TИз оптимизации только контроль задвоений счетчиков.Можно еще взаимные делители контролировать.
Например, если есть P 1 =2 и P 2 =4, то они при объединении дают ту же 4, но со сдвигом на 2.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170779
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, единственное, что увидел:

при подсчете результата развернуть цикл в 4 раза,
и тогда можно будет обнулять по 32 бита за раз.
Но это копейки.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170785
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miksoftDima TИз оптимизации только контроль задвоений счетчиков.Можно еще взаимные делители контролировать.
Например, если есть P 1 =2 и P 2 =4, то они при объединении дают ту же 4, но со сдвигом на 2.
Тоже думал, но это только если P 2 / P 1 = 2, счетчики step * P 1 и step * P 2 сводятся к счетчику P 1 + step * P 2
Если P 2 / P 1 = 3 уже так не сделать.
Т.е. идеале убираем до половины счетчиков.

Хотя может и взлетит.
Самый жестокий тест у меня cчитается 3 сек
Код: sql
1.
2.
1000000000 50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 45 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

Только четные - 1,6 сек
Код: sql
1.
2.
1000000000 25
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50


На грани фола, не факт что там такой же быстрый проц. Попробую затестить.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170791
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добавил склеивание двухкратных. Не помогло. Time limit exceeded
У меня время самого жесткого теста 1,4 сек. Жалко что у них не i7
Исходник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
#include <fstream>
#include <iostream>
using namespace std;

#include <stdio.h>
#include <time.h>

// Размер окна биткарты в байтах
#define BM_SIZE 8192 // 8 Kb

int main(int argc, char**argv)
{
	// Считывание задания
	ifstream in("input.txt");
	int N, K;
	in >> N >> K;
	bool P[51] = { 0 };
	int cnt = 0; // кол-во полезных счетчиков
	for (int i = 0; i < K; i++) {
		int v;
		in >> v;
		P[v] = !P[v];
		if (P[v]) {
			cnt++;
		} else {
			cnt--;
		}
	}
	if (P[1]) cnt--; // единицы не считаем

	int res = 0;
	if (cnt) {
		int* steps = (int*)calloc(cnt, sizeof(int)); // шаги счетчиков
		int* values = (int*)calloc(cnt, sizeof(int)); // значения счетчиков
		for (int i = 2, j = 0; i <= 50; i++) {
			if (P[i]) {
				if(i <= 25 && P[i * 2]) {
					// Объединение счетчиков с шагом отличающимся вдвое
					steps[j] = i * 2;
					values[j] = i;
					P[i * 2] = false;
					cnt--;
				} else {
					steps[j] = i;
					values[j] = i;
				}
				j++;
#ifdef _DEBUG
				cout << i << " ";
#endif
			}
		}
		// Для подсчета единичных бит в байте
		int bit_cnt[256] = { 0 };
		for (int i = 0; i < 256; i++) {
			int n = i;
			while (n != 0) {
				bit_cnt[i]++;
				n = n & (n - 1);
			}
		}
		// Биткарта
		unsigned char* bm = (unsigned char*)calloc(BM_SIZE, 1);
		int next = 0;
		while (next <= N) {
			int start = next;
			next += BM_SIZE * 8;
			if (next > N) next = N + 1;
			// Заполнение окна биткарты
			for (int i = 0; i < cnt; i++) {
				int lim = next - start; // конец биткарты
				int v = values[i] - start, s = steps[i];
				for (; v < lim; v += s) {
					bm[v >> 3] ^= (1 << (v & 7));
				}
				values[i] = v + start;
			}
			// считывание результата
			for (int i = 0; i < BM_SIZE; i++) {
				res += bit_cnt[bm[i]];
				bm[i] = 0;
			}
		}
	}
	// Инверсия если была единица
	if (P[1]) res = N - res;
	// Вывод результата
	ofstream out("output.txt");
	out << res << endl;
	out.close();
	cout << endl << "time " << clock() << endl;
	cout << "Result " << res << endl;
	return 0;
}

...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170794
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно еще запараллелить, но как-то не спортивно это, и не факт что там ядер больше одного :)
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170797
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут надо формулу изобретать. Все что смог изобрести:
если НОД(а, b) = 1, то на интервале N результат будет N/a + N/b - N/(2 * a * b)
С тремя уже непонятно, НОД(а, b) > 1 тоже непонятно.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170798
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

а что не хочешь сделать подсчет (чтение окна) и обнуление двордами?
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170802
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть еще мысль: можно ксорить биткарты. Например есть счетчики (a,b,c,d,e,f) повторяемость (a,b,c) K 1 , (d,e,f) K 2 , делаем две биткарты БК 1 и БК 2 дальше проход по ним подсчет бит в XOR(БК 1 [i % K 1 ], БК 2 [i % K 2 ]) можно третью и т.д. добавить, но тут главное чтобы все K i были выравняны, т.е. кратны 8. В этом засада. Еще проблема из-за ограничения памяти, т.е. разбить счетчики на группы так чтобы сумма(K i ) была меньше 16 Мб
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170806
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima T,

а что не хочешь сделать подсчет (чтение окна) и обнуление двордами?
Сделал еще быстрее
Код: plaintext
1.
2.
3.
4.
5.
			for (int i = 0; i < BM_SIZE; i++) {
				res += bit_cnt[bm[i]];
				//bm[i] = 0;
			}
			memset(bm, 0, BM_SIZE);


у меня c 1,4 ускорилось до 1,24 сек., но там все-равно не пролез по времени.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170808
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

да не быстрее это )

читай двойное слово, потом для каждого прочитанного байта сумма, потом пишешь 0 двойным словом.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170818
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima T,

да не быстрее это )

читай двойное слово, потом для каждого прочитанного байта сумма, потом пишешь 0 двойным словом.
Написал так
Код: plaintext
1.
2.
3.
4.
			for (int i = 0; i < BM_SIZE; i += 4) {
				res += bit_cnt[bm[i]] + bit_cnt[bm[i + 1]] + bit_cnt[bm[i + 2]] + bit_cnt[bm[i + 3]];
				*((int*)&bm[i]) = 0; // обнулить сразу 4 байта i ... i+3
			}


стало 1.6 сек. Предлагай свой вариант.

имху быстее memset() вряд ли получится, это функция для обнуления блока памяти и ее реализация в компиляторе отточена до идеала.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170819
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

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

Так по идее быстрее - на три чтения меньше.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170823
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Написал так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
			for (int i = 0; i < BM_SIZE; i++) {
				res += bit_cnt[bm[i]];
				//bm[i] = 0;
			}
			for (int i = 0; i < BM_SIZE; i += 4) {
				*((int*)&bm[i]) = 0; // обнулить сразу 4 байта i ... i+3
			}


стало 1,23, т.е. на 0,01 сек быстрее. Некуда в эту сторону двигаться. Разве что оба цикла пытаться на асме переписать, и то не факт что быстрее станет.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170826
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, а почему бы все таки, наконец, не сделать так, как я написал )

Так будет и быстрый подсчет, и обнуление ЗАДАРОМ.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170827
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima T,

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

Так по идее быстрее - на три чтения меньше.
Ступил. Чуть быстрее. 1.15 сек стало.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
			for (int i = 0; i < BM_SIZE; i += 4) {
				unsigned int k = *((int*)&bm[i]);
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				*((int*)&bm[i]) = 0;
			}



Но тест не проходит по времени.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170831
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, еще быстрее

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
for (int i = 0; i < BM_SIZE; i += 4) {
				unsigned int k = *((int*)&bm[i]);
				res += bit_cnt[k & 0xFF];
				res += bit_cnt[(k >>8) & 0xFF];
				res += bit_cnt[(k >>16_ & 0xFF];
				res += bit_cnt[k >>24];
				*((int*)&bm[i]) = 0;
			}
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170837
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima T, еще быстрее

Нет. Медленнее. 1,55 сек. Тут k надо перечитывать. У меня не надо. Она в регистре живет.

Можно еще подобным образом пошаманить над циклом заполнения
Код: plaintext
1.
2.
3.
4.
5.
				int lim = next - start; // конец биткарты
				register int v = values[i] - start, s = steps[i];
				for (; v < lim; v += s) {
					bm[v >> 3] ^= (1 << (v & 7));
				}


сделать обращение к биткарте 4хбайтным и v >> 3 как-то оптимизировать, т.к. в 32 бита по несколько раз много счетчиков попадает.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170841
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это шаманство дает копеечное ускорение. Я бы все-таки копал в сторону уменьшения количества счетчиков. Сейчас их 25. Шаг
Код: sql
1.
4 6 10 14 16 18 22 24 26 30 34 38 40 42 46 50 27 28 29 31 32 33 36 37 39 41 43 44 47 48 49


хотя бы как-то убрать самые частые: 4 6 10
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170842
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Ясно.
С заполнением бит-карты вряд ли быстрее удастся.
Можно, конечно, немного поиграть с разворачиванием цикла.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170847
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Посчитал сколько бит сбрасывается из 1 в ноль
Код: plaintext
1.
2.
3.
4.
				for (; v < lim; v += s) {
					if ((bm[v >> 3] & (1 << (v & 7))) != 0) cnt_bad++;
					bm[v >> 3] ^= (1 << (v & 7));
				}


Код: sql
1.
cnt_bad 429321267


потенциальная возможность для ускорения совершенствованием алгоритма.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170850
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЭто шаманство дает копеечное ускорение. Я бы все-таки копал в сторону уменьшения количества счетчиков. Сейчас их 25. Шаг
Код: sql
1.
4 6 10 14 16 18 22 24 26 30 34 38 40 42 46 50 27 28 29 31 32 33 36 37 39 41 43 44 47 48 49


хотя бы как-то убрать самые частые: 4 6 10

счетчики 4, 16, 32, 34, 36, 40, 48 можно сделать двумя битовыми масками
при подсчете результата, если цикл развернуть еще вдвое.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170856
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov, ошибочка

только счетчики 4, 16, 32 можно сделать одной битовой маской при подсчете результата
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170858
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovсчетчики 4, 16, 32, 34, 36, 40, 48 можно сделать двумя битовыми масками
при подсчете результата, если цикл развернуть еще вдвое.
не понял о чем речь, давай поподробнее.

только не забывай что мы их уже один раз модифицировали 18815259 :
4 это 2+4k, т.е. с 2 шаг 4
16 это 8+16k
и т.д.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170861
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

по всем счетчикам, на которые делится 32
(они дают повторы битов через 32)
один раз формируем маску mask, и далее

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
for (int i = 0; i < BM_SIZE; i += 4) {
				unsigned int k = *((int*)&bm[i]) xor mask;
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				k >>= 8;
				res += bit_cnt[k & 0xFF];
				*((int*)&bm[i]) = 0;
			}



естественно, эти счетчики не участвуют в заполнении бит-карты.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170865
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
последействие паскаля, вместо xor надо было ^
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170868
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima T,

по всем счетчикам, на которые делится 32
(они дают повторы битов через 32)
один раз формируем маску mask, и далее
понял, сегодня уже плохо соображаю, завтра затестю.
Я еще голову ломаю как бы счетчики с отношением 3 склеить. Там шаг должен быть 1,2,1,2 т.е. можно менять шаг битовым сдвигом туда-обратно после каждого шага. Это в мыслях пока.

текущий вариант исходника
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
#include <fstream>
#include <iostream>
using namespace std;

#include <stdio.h>
#include <time.h>
#include <string.h>

// Размер окна биткарты в байтах
#define BM_SIZE 8192 // 8 Kb

int main(int argc, char**argv)
{
	// Считывание задания
	ifstream in("input.txt");
	int N, K;
	in >> N >> K;
	bool P[51] = { 0 };
	int cnt = 0; // кол-во полезных счетчиков
	for (int i = 0; i < K; i++) {
		int v;
		in >> v;
		P[v] = !P[v];
		if (P[v]) {
			cnt++;
		} else {
			cnt--;
		}
	}
	if (P[1]) cnt--; // единицы не считаем

	int res = 0;
	if (cnt) {
		int* steps = (int*)calloc(cnt, sizeof(int)); // шаги счетчиков
		int* values = (int*)calloc(cnt, sizeof(int)); // значения счетчиков
		for (int i = 2, j = 0; i <= 50; i++) {
			if (P[i]) {
				if(i <= 25 && P[i * 2]) {
					// Объединение счетчиков с шагом отличающимся вдвое
					steps[j] = i * 2;
					values[j] = i;
					P[i * 2] = false;
					cnt--;
				} else {
					steps[j] = i;
					values[j] = i;
				}
				j++;
#ifdef _DEBUG
				cout << steps[j - 1] << " ";
#endif
			}
		}
		// Для подсчета единичных бит в байте
		int bit_cnt[256] = { 0 };
		for (int i = 0; i < 256; i++) {
			int n = i;
			while (n != 0) {
				bit_cnt[i]++;
				n &= (n - 1);
			}
		}
		// Биткарта
		unsigned char* bm = (unsigned char*)calloc(BM_SIZE, 1);
		int next = 0;
		//int cnt_bad = 0;
		while (next <= N) {
			int start = next;
			next += BM_SIZE * 8;
			if (next > N) next = N + 1;
			// Заполнение окна биткарты
			for (int i = 0; i < cnt; i++) {
				int lim = next - start; // конец биткарты
				register int v = values[i] - start, s = steps[i];
				for (; v < lim; v += s) {
					//if ((bm[v >> 3] & (1 << (v & 7))) != 0) cnt_bad++;
					bm[v >> 3] ^= (1 << (v & 7));
				}
				values[i] = v + start;
			}
			// считывание результата
			for (int i = 0; i < BM_SIZE; i += 4) {
				register unsigned int k = *((int*)&bm[i]);
				res += bit_cnt[k & 0xFF];
				res += bit_cnt[(k >> 8) & 0xFF];
				res += bit_cnt[(k >> 16) & 0xFF];
				res += bit_cnt[k >> 24];
				*((int*)&bm[i]) = 0;
			}
		}
		//cout << "cnt_bad " << cnt_bad << endl;
	}
	// Инверсия если была единица
	if (P[1]) res = N - res;
	// Вывод результата
	ofstream out("output.txt");
	out << res << endl;
	out.close();
	cout << endl << "time " << clock() << endl;
	cout << "Result " << res << endl;
	return 0;
}

...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170872
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Я еще голову ломаю как бы счетчики с отношением 3 склеить.
Там шаг должен быть 1,2,1,2 т.е. можно менять шаг битовым сдвигом туда-обратно после каждого шага.


Это просто: step=3-step.
Придется хранить не 2, а 3 описателя для каждого счетчика.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170876
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, не будет так быстрее?

Код: plaintext
1.
2.
3.
4.
res += bit_cnt[k & 0xFF]
	+ bit_cnt[(k >> 8) & 0xFF]
	+ bit_cnt[(k >> 16) & 0xFF]
	+ bit_cnt[k >> 24];
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170879
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovКстати, не будет так быстрее?

Код: plaintext
1.
2.
3.
4.
res += bit_cnt[k & 0xFF]
	+ bit_cnt[(k >> 8) & 0xFF]
	+ bit_cnt[(k >> 16) & 0xFF]
	+ bit_cnt[k >> 24];


так еще медленнее. Что-то у меня 1,15 сек 18815517 опять вырасли до 1,4. хз чего направил завтра перепроверю.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170880
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tпонял, сегодня уже плохо соображаю, завтра затестю.


Там есть пара тонких мест:
1) кратность размера окна 4 байтам (32 битам) - ну это и так есть,
2) кратность общего количества лампочек 32 - если ее нет,
то придется вычесть лишние висячие биты маски.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170886
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovDima Tпонял, сегодня уже плохо соображаю, завтра затестю.


Там есть пара тонких мест:
1) кратность размера окна 4 байтам (32 битам) - ну это и так есть,
2) кратность общего количества лампочек 32 - если ее нет,
то придется вычесть лишние висячие биты маски.
1. есть
2. есть. Заполнение биткарты счетчиками заканчивается на N, а вот с масками на 4,16,32 это надо будет учесть.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170889
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ого тут букв!

А пробовали учесть повторы делителей 3,4,5 ?

Код: sql
1.
1 2 7 3*3 13 4*4 19 23 5*8 5*9
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170901
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

пока что ясно:
1) шаги 2, 4, 8, 16, 32 учитываются одной общей маской при подсчете суммы,
2) шаги X и 2X заменяются одним сдвинутым шагом 2X,
3) шаги X и 3X заменяются одним переменным сдвинутым шагом 2X/2

остальное пока неясно.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170908
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
опечатка
3) шаги X и 3X заменяются одним переменным сдвинутым шагом 2X/X
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39170995
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Восстановил исходник, который работал 1,15 сек.

ИМХУ склеивание счетчиков тупиковый путь. Для того что очевидно как клеить (типа кратных двум) скорее всего сделали тесты так чтобы клеить было нечего.

Переделал наихудшие тесты с учетом нашей оптимизации по склеиванию кратных двум.
это считается 1,75 сек
Код: sql
1.
2.
1000000000 32
1 2 3 5 7 9 11 13 15 17 19 23 25 27 28 29 31 32 33 45 36 37 39 40 41 42 43 44 45 47 48 49


это считается 1,4 сек и никак не склеится
Код: sql
1.
2.
1000000000 16
2 3 5 7 11 13 17 19 23 29 31 37 39 41 43 47


Мне кажется надо в первую очередь оптимизировать малые счетчики, т.к. там проходов больше всего
СчетчикИтерацийДоля250000000014.3%33333333339.5%42500000007.1%52000000005.7%61666666664.8%71428571424.1%81250000003.6%
Счетчики 2,4,8,16,32 суммарно 27,7% итераций. Оптимизация масками должна заметно их ускорить.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171002
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любые малые счетчики можно масками наносить, просто надо сдвиг дополнительный, например для 3x:
Код: sql
1.
2.
3.
4.
5.
01001001
10010010
00100100
01001001
...


для 5 уже таблица сдвигов [3,1,4,2 ...]

Думаю можно развить эту идею: 18815352 заготовить каждому счетчику биткарту выравненную по 4 байтам и наносить счетчики биткартами. В каждой биткарте байт будет не более значение счетчика * 4.

Для 2,4,8,16,32 можно одну общую биткарту использовать.

Для счетчиков кратных 2,4,8,16 тоже общие биткарты можно. Например 5, 20, 40 должны объединиться на биткарте 40, если не напутал.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171010
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, думаю, ощутимый выигрыш даст только маска для степеней двойки.

Для других сдвигов маска малопригодна,
т.к. придется работу переносить в подсчет,
а там будет довольно накладно запоминать
состояния переменного числа шагов.

Ну, может быть, стоит шаг=3 отдельно учесть.
Т.е. делаем размер окна кратным 12 байт,
и если тройка есть среди множителей,
то подсчет идет другим циклом, развернутым в 3 раза.
Можно и подсчет без тройки тоже развернуть.

И, думаю, от склейки по 2 не стоит отказываться, т.к. она дается даром.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171013
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Склейка 1 к 3 или 2 к 3 тоже достаточно дешева:
для всех таких (1 к 3 или 2 к 3) заполнение окна
делаем в другом цикле, который отличается от твоего
одним лишним вычитанием в теле цикла step=m-step
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171016
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ты не понял, для счетчика один раз инициализируется биткарта, примеры на 8-битовых (биты в обратном порядке 0-7 для наглядности):
Код: sql
1.
2.
3.
3 = 10010010,01001001,00100100
5 = 10000100,00100001,00001000,01000010,00010000
6 = 10000010,00001000,00100000,10000010,00001000,00100000


дальше просто зацикливаем маску и по кругу.

Предыдущая оптимизация с двойками не теряется, но и добавляются новые. Например маска для 3 дважды ложится в 6, т.е. их склеиваем при инициализации. То же самое с 12, туда лезут 3,6. В 48 влезут 2,3,4,6,8,12,16,24.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171018
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем вся математика на этапе инициализации, во время расчета тупо XOR двойными словами( по 32 бита) и подсчет результатов.
Даже изврата с единицей не надо, ее в любую маску можно добавить.
Должно сработать.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171020
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я понял, потому что думал над этим раньше )
Тут очень большая проблема, которая почти наверняка потребует
создание внутреннего цикла внутри подсчета и работы с памятью.

Тройку (и если хочешь простыню - пятерку) можно учесть
масками без доп. работы, если развернуть цикл.
Но не более.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171024
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
разумеется, при этом под оптимизацию попадают все делители чисел 96 и 160
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171025
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вторым шагом можно досклеить полученные биткарты пока пямяти хватает: например 13 и 17 склеятся в 884 байта (13 * 17 * 4). Хотя тут не факт что ускорение будет, т.к. маленькие вместе влезут в кэш проца, большие будут из памяти подкачиваться постоянно. С другой стороны чем меньше биткарт, тем быстрее будет считаться.

Пока некогда, ближе к вечеру постараюсь написать.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171411
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Написал. Летает. 50 счетчиков до лярда 0,2 сек.

Но это 0.42 сек.
Код: sql
1.
2.
1000000000 17
2 3 5 7 11 13 17 19 23 29 31 37 39 41 43 47 49



медленнее потому что склейка счетчиков не самая лучшая. В первом случае 50 склеилось в 4 счетчика, во втором всего в 9, хотя можно минимум в 4.

Надо какой-то оптимальный алгоритм склейки. Суть в следующем:
счетчик a занимает size_a = НОК(а,4) байта, счетчик b - size_b = НОК(b,4) байт, при слиянии займут size_ab = НОК(size_a, size_b)
например а = 11 тогда size_a = 44, b = 18 => size_b = 36, после слияния счетчик ab займет size_ab = 396
И тут их надо так слить чтобы суммарно они не вылезли за 16 Мб. Я поставил 14.
ХЗ как комбинировать. Пока сделал так: берем последний, поиск такого с которым size_ab минимальное, если нашли и памяти достаточно - слияние.

ХЗ как оптимизировать. Факторизация и ... ?

PS Сайт для проверки лежит, пока не затестить, но думаю пройдет тест. Исходник выкладывать или пусть желающие сами пишут по инструкции выше ?
PPS Ссылку Fort Knox почитал по диагонали, нифига не понял.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171426
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или по другому, в случае ряда простых чисел типа
Код: sql
1.
3 5 7 11 13 17


разбить их на минимальное количество групп, так чтобы сумма произведений членов каждой группы была меньше заданного предела.
например две группы
Код: sql
1.
(3*5*7) + (11*13*17) < MAX


Если в одну не сливается, то данное решение уже идеально, т.к. принципиально минимизировать количество групп, а не результат.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171495
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
50 в 4 слилось так (лог)
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
Исходный -> групповой
50->0
49->1
48->2
47->3
46->4
44->5
43->6
42->7
41->8
40->0
39->9
38->10
37->11
36->12
34->13
33->14
32->0
31->15
30->16
29->17
28->1
27->18
26->9
25->0
24->2
23->4
22->5
21->7
20->0
19->10
18->12
17->13
16->0
15->16
14->1
13->9
12->2
11->5
10->0
9->12
8->0
7->1
6->2
5->0
4->0
3->2
2->0
1->0
Слияние групповых
[18] => [2]
[17] => [12]
[16] => [0]
[15] => [5]
[14] => [7]
[13] => [10]
[12] => [2]
[11] => [4]
[10] => [9]
[9] => [0]
[8] => [6]
[7] => [1]
[6] => [3]
[5] => [1]
[4] => [2]

при загрузке склеиваются только если меньший влазит в больший кратно 2 раз
ГрупповойИсходные01 2 4 5 8 10 16 20 25 32 40 5017 14 28 4923 6 12 24 483 474 23 46511 22 44643721 42841913 26 391019 381137129 18 361317 34143315311615 3017291827

После слияния групповых стало так
ГрупповойИсходные01 2 4 5 8 10 16 20 25 32 40 50 15 30 13 26 39 19 38 17 3417 14 28 49 21 42 33 11 22 44 3123 6 12 24 48 27 9 18 36 29 23 46 373 47 43 41
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171520
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TНаписал. Летает.

Здорово, если пройдет тест на скорость.

Dima TСсылку Fort Knox почитал по диагонали, нифига не понял.

Дык, XOR множеств.
Отличие от формулы включений-исключений только в том,
что надо дважды вычитать то, что пересеклось.

По идее слагаемых должно быть 2^x,
но реально их намного меньше,
т.к. лампочки, входящие в пересечение нескольких множеств
часто оказываются дальше последней.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171618
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T, я чувствуется опыт Решета Эратосфена.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171775
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonDima T, я чувствуется опыт Решета Эратосфена.
Тут все из него. От теории до реализации.

Придумал оптимизацию счетчиков. Сворачивается в 4 счетчика. Время 0.3-0.4 сек на самых тяжелых случаях.

Никто не высказался против выкладывания исходника, поэтому выкладываю. Думаю рядовым студентам он бесполезен, а олимпийцы только опыта поднаберутся. Тупым гуглением олимпиаду не выиграть.
Исходник (многа букав)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
// http://acmp.ru/index.asp?main=task&id_task=337

#include <fstream>
#include <iostream>
#include <vector>
#include <map>
using namespace std;

#include <stdint.h>
#include <stdio.h>
#include <time.h>

//#define MAX_MEMORY 4194304 // 4 Мб
//#define MAX_MEMORY 8388608 // 8 Мб
#define MAX_MEMORY 14680064 // 14 Мб

// НОД
int64_t gcd(int64_t a, int64_t b) {
	return b ? gcd(b, a % b) : a;
}

// НОK
int64_t lcm(int64_t a, int64_t b) {
	return a / gcd(a, b) * b;
}

//Макс простой множитель
int max_prime(int n) {
	static int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 };
	if (n == 1) return 1;
	int* m = primes;
	while(n > 1) {
		if((n % *m) == 0) {
			n /= *m;
		} else {
			m++;
		}
	}
	return *m;
}

// Класс счетчика
class cnt_t {
	uint32_t* bm; // биткарта
	size_t size; // Размер в битах
	uint32_t* cur; // текущий элемент для перебора
	uint32_t* end; // конец bm
public:
	cnt_t() {
		bm = NULL;
	}

	~cnt_t() {
		if(bm != NULL) free(bm);
	}

	// Инициализация
	void init(int value) {
		size = lcm(value, 32);
		bm = (uint32_t*)calloc(size / 32, 4);
		cur = bm;
		end = bm + (size / 32);
		for (uint32_t i = 0; i != size; i += value) {
			bm[i >> 5] ^= (1 << (i & 31));
		}
	}

	// Склеивание с другим счетчиком
	bool clue(cnt_t& c) {
		size_t new_size = lcm(size, c.size);
		if(new_size > size) {
			uint32_t* bm_new = (uint32_t*) realloc(bm, new_size / 8);
			if (!bm_new) return false;
			bm = bm_new;
			cur = bm;
			end = bm + (size / 32);
			uint32_t* new_end = bm + (new_size / 32);
			for (uint32_t* p = end; p < new_end; p++) {
				*p = next();
			}
			size = new_size;
			cur = bm;
			end = new_end;
		}
		c.cur = c.bm;
		for (uint32_t* p = bm; p < end; p++) {
			*p ^= c.next();
		}
		return true;
	}

	// Склеивание с другим исходным счетчиком
	bool clue(int i) {
		if(add(i)) {
			return true;
		} else {
			cnt_t c;
			c.init(i);
			return clue(c);
		}
	}

	// Добавление счетчика. Возвращает false - если невозможно добавить
	bool add(int value) {
		size_t new_size = lcm(value, 32);
		if (size != new_size && size % new_size != 0) {
			// Не входит кратно
			return false;
		}
		for (uint32_t i = 0; i != size; i += value) {
			bm[i >> 5] ^= (1 << (i & 31));
		}
		return true;
	}

	// Перенос в другой счетчик
	void move(cnt_t& c) {
		if (c.bm != NULL) free(c.bm);
		c.bm = bm;
		c.cur = cur;
		c.end = end;
		c.size = size;
		bm = NULL;
	}

	// Занято памяти, байт
	uint32_t total() {
		return size / 8;
	}

	// Следующие 32 бита (лампочки)
	uint32_t next() {
		if (cur == end) cur = bm;
		return *(cur++);
	}
};


int main(int argc, char**argv)
{
	// Считывание задания
	ifstream in("input.txt");
	int N, K;
	in >> N >> K;
	bool P[51] = { 0 };
	for (int i = 0; i < K; i++) {
		int v;
		in >> v;
		P[v] = !P[v];
	}
	// Распределение по счетчикам (для каждого mp свой счетчик)
	vector<cnt_t> counters;
	map<int, int> mp_idx;
	counters.reserve(12);
	int k_init = 0;
	for (int i = 50; i > 0; i--) {
		if (P[i]) {
			k_init = 1 - k_init;
			int mp = max_prime(i);
			if (mp < 11) mp = 11; // все маленькие в один
			map<int, int>::iterator it = mp_idx.find(mp);
			if (it != mp_idx.end()) { // Счетчик уже есть
				if (!counters[it->second].clue(i)) {
					it = mp_idx.end(); // Не склеилось
				} else {
#ifdef _DEBUG
					cout << endl << i << "->" << it->second;
#endif
				}
			}
			if(it == mp_idx.end()) { // Добавление счетчика
				counters.push_back(cnt_t());
				counters[counters.size() - 1].init(i);
				mp_idx[mp] = counters.size() - 1;
#ifdef _DEBUG
				cout << endl << i << "->" << mp_idx[mp];
#endif
			}
		}
	}
	int total = 0;
	for (int i = 0; i < counters.size(); i++) {
		total += counters[i].total();
	}
#ifdef _DEBUG
	cout << endl << "memory " << total;
#endif
	// Склеивание счетчиков
	int prev = 0;
	while(prev != counters.size()) {
		prev = counters.size();
		// поиск минимального
		int add_idx = prev - 1;
		int size_test = counters[add_idx].total();
		for (int i = 0; i < prev - 2; i++) {
			if(size_test > counters[i].total()) {
				size_test = counters[i].total();
				add_idx = i;
			}
		}
		int64_t min = MAX_MEMORY - total + size_test;
		int min_idx = prev;
		// Поиск наименьшего размера после склеивания
		for (int i = 0; i < prev; i++) {
			if (i == add_idx) continue;
			int64_t new_size = lcm(size_test, counters[i].total());
			if(min > new_size) {
				min = new_size;
				min_idx = i;
			}
		}
		if(min_idx != prev) {
			total += (int)min - size_test;
			if (total > MAX_MEMORY) break;
			if(counters[min_idx].clue(counters[add_idx])) {
#ifdef _DEBUG
				cout << endl << "[" << add_idx << "] => [" << min_idx << "] " << "memory " << total;
#endif
				if(add_idx != prev - 1) { // непоследний
					counters[prev - 1].move(counters[add_idx]);
				}
				counters.pop_back();
			}
		}
	}
	cout << endl << "counters " << counters.size() << " memory " << total / 1024 << "Kb";
	// Для подсчета единичных бит в байте
	int bit_cnt[256] = { 0 };
	for (int i = 0; i < 256; i++) {
		int n = i;
		while (n != 0) {
			bit_cnt[i]++;
			n &= (n - 1);
		}
	}
	// Расчет
	int res = 0;
	cnt_t* start = &counters[0];
	cnt_t* end = start + counters.size();
	int next = 0;
	register uint32_t k = k_init;
	while (true) { // Самый тяжелый цикл
		// Очередная порция лампочек
		for (cnt_t* c = start; c < end; c++) {
			k ^= c->next();
		}
		next += 32;
		// подсчет лампочек (бит)
		if(next <= N) {
			res += bit_cnt[k & 0xFF];
			k >>= 8;
			res += bit_cnt[k & 0xFF];
			k >>= 8;
			res += bit_cnt[k & 0xFF];
			k >>= 8;
			res += bit_cnt[k];
			k = 0;
		} else {
			for (int i = next - 32; i <= N; i++) {
				if ((k & 1) != 0) res++;
				k >>= 1;
			}
			break;
		}
	}
	// Вывод результата
	ofstream out("output.txt");
	out << res << endl;
	out.close();
	cout << endl << "time " << clock() << endl;
	cout << "Result " << res << endl;
	return 0;
}



PS На проверку не отправил, т.к. сайт-проверялка лежит. У меня итого сходится с предыдущими реализациями. Завтра утром зашлю, если оживет.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39171977
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonDima T, я чувствуется опыт Решета Эратосфена.
Только сейчас понял что тогда к Эратосфену надо было прикрутить эту идею со склеивающимися счетчиками, а то я какие-то велосипеды с квадратными колесами изобретал в виде счетчиков с переменным шагом 17486621 . В итоге вся оптимизация закончилась на 3-ке, а так можно заготовку биткарты сделать и ее использовать для инициализации (для 2,3,5,7,11 потребуется всего 9 Кб). Надо будет добавить туда как-нибудь. А то я там "рекорды" ставил распараллеливанием на 4 ядра. Судя по этим замерам там тоже должно ускориться в 3-5 раз.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39177350
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Задача сдана ? Не могу даже условие посмотреть
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39177848
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не сдана. Там все сломалось
http://acmp.ru/index.asp?r=151923784153675657266782 [20.02] Уважаемые пользователи! В связи с техническими сложностями (вышел из строя веб-сервер) сайт был недоступен и в настоящее время используется его копия. В связи с малой мощностью предоставленного сервера возможность авторизации пользователям будет ограничена (участники раздела "Курсы", спонсоры и т.д. смогут решать задачи в любое время, остальные - по воскресеньям и с 17:00 до 4:00 в другие дни)...
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179142
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот к чему приводит возведение 99 десять раз в степень 99.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179174
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Заслал на проверку. Прошел все тесты. Время 0,397 сек.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179239
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ты крут как варёные яйца.

А я щас делаю задачу с укладкой домино.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179290
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maytonТы крут как варёные яйца.

А я щас делаю задачу с укладкой домино.
в пятничную тему не выноси. Не сдержусь
Работы навалили со всех сторон одновременно. Я в Эратосфена начал вписывать то что тут родилось, взлетел он немного с 23 до 27 млн в сек., но не все дописал. Мысли еще есть, времени пока нет. С паспортами тоже почти закончил 18772620 , чуть-чуть доделать, потестить и готовый продукт будет.
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179463
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЗаслал на проверку. Прошел все тесты. Время 0,397 сек.

Поздравляю ;)
...
Рейтинг: 0 / 0
Тяпничные лампочки
    #39179680
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TmaytonТы крут как варёные яйца.

А я щас делаю задачу с укладкой домино.
в пятничную тему не выноси. Не сдержусь
Работы навалили со всех сторон одновременно. Я в Эратосфена начал вписывать то что тут родилось, взлетел он немного с 23 до 27 млн в сек., но не все дописал. Мысли еще есть, времени пока нет. С паспортами тоже почти закончил 18772620 , чуть-чуть доделать, потестить и готовый продукт будет.
И не подумаю. Я до 4.00 утра просидел с домино. Пока не понял что алгоритм волны не покрывает
общий случай. И нужен поиск в глубину.

Да ну ево в пень. Будет настроение - опубликую.
...
Рейтинг: 0 / 0
92 сообщений из 92, показаны все 4 страниц
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничные лампочки
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]