powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничные лампочки
25 сообщений из 92, страница 2 из 4
Тяпничные лампочки
    #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
25 сообщений из 92, страница 2 из 4
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничные лампочки
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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