На форумі обговорюються лише питання, пов'язані з олімпіадою
Ви не зайшли.
60 балов CD:
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int cnt=0;
int temp,prev=-1;
for(int i=0;i<n;i++)
{
cin>>temp;
if(i==0) cnt++;
else if(prev!=temp) cnt++;
prev=temp;
}
cout<<cnt-prev<<endl;
return 0;
}как я делал
ДВД:
1-е сделать вектор отрезков рабочего времни
2-е разбил его нерабочим временем - у нас получилось некое количество откезков который можно использовать
3-е разбил наши рабочие отрезки так: у каждого отверза три параметра - начало, конец, тип(4q,2q,q) и жадным алгоритмом каждый отрезок разбиваю на мелкие по 4q потом что останеться по 2q и потом по 3q
4-е если наших отрезков меньше чем нужно дисков, то сначала ищем и разбиваем отрезки 4q по 2q - так как было качество 3 станет 2+2=4 и увелисится диск, если разбиений 4q не хватает, то разбиваем 2q по q , нужно сначала рахбивать 4q так как 2+2=4, 2q: 1+1=2, тоесть качество будет больше
5-е подсчет, сначала считаем все там где 4q и удаляем эти отрезки, если дисков еше нехватает то считаем 2q и потом просто q
ну вот это решение должно проходить, но я криво закодил ![]()
Case:
если сделать матрицу связи група/люди
например:
вверху група, с боку люди
1234
1 х___
2 х__х
3 _хх_
4 ххх_
5 хххх
6 ___х
"х"-связть есть, "_" - нету
и нам нужно использую только точки "х"
найти расстановку шахматных тур(ладья) в количестве равным количеству груп
а остальных людей определить в любую групу к которой они пренадлежат - я делал рекурсия с откатом
Woods я незнаю как делать
чета неувидил ![]()
Border сейчас сделаю рисунок и напишу
Поза форумом

вот картинка для бордера
пусть угол гамма = G, бетта = B, Альфа - L
мы можем узнать угол L через треугольник O1O2 и точки внизу, потом берем арккосинус/арктангенс пот у нас есть угол L
чтобы найти угол B = arccos((R1-R2)/O1O2);
угол G = PI-L-G;
и теперь у нас есть угол G и R круга, находим через косинус/синус угла смещенние по X и по Y
для кольца с меньшим радиусом
X=r*cos(L);
Y=r*sin(L);
ВОт это теория, в задаче же я так и несмог закодить так это то что смещение по X Y для обоих окружнойстей может быть с разными знаками в зависимости от их взаимного расположение, тоесть толи как на рисунке, толи с больши радиусом внизу, с меньшим вверху
для каждый хвух колец мы знаем 2 касательный - сверху и снизу,
нужно закодить также определение какую касательную брать - нужно брать или все внутринии или все внешние
потом строим выпуклую оболочку:
берем три круг находим от двух из них касетльные к третему, получиться 2 отрезка - делаем из них прямую, находим точку пересечение и считаем угол который они делают, и по этому углу строим выпуклую оболочку
есть еше один вариант - для каждой касательный проверять чтобы ВСЕ остальный окружности лежали от нее с другой стороны , если так и есть то это будет какаято крайняя, если касательная пересекает хотябы одну из других окружностей или какихто 2 центра окружностей лежат с двух сторон - брать нельзя
вот так я хотел кодить, но всетаки не закодил, так как идея пришла только дня два назад и времени не хватало(учеба+подготовка к ЗНО...)
если есть варианты по проще и будут работать с такойже точностью как и этот с удовольствием выслушаю
кстати думал еше над одним способом - разбить каждый круг на набор точек и строить по ним, но я так и не смог достигнуть нужной точности и приемлемого времени выполнения!
Відредаговано Cris (2010-01-30 12:16:02)
Поза форумом
ага, бордер и двд сделал также, но время неприемлимо 0.05 сек и получил за них 0 баллов=))
Поза форумом
CD:
#include <iostream>
using namespace std;
int main()
{
int N, k = 0, l, m;
cin >> N >> l;
while (--N) {
cin >> m;
if (m != l) {
++k;
l = m;
}
}
if (!l)
++k;
cout << k;
return 0;
}Case:
Поиск полного паросочетания в двудольном графе.
(Алгоритм Хопкрофта-Карпа)
Border:
геометрия
Відредаговано Vinnie (2010-01-30 12:49:20)
Поза форумом
как Woods делать?
Поза форумом
я точно знаю, що в woods якщо нема обмеженнь(s=0) то кількість перестановок=k^(2*n)
Поза форумом
Там використовуються наступні співвіднощення:
F(i,K1,K2) - кількість можливих заповнень перших і стовпчиків таблиці так, що в і-тому знаходяться дерева типів К1 і К2.
F(1,K1,K2)=
1).1 якщо пара (К1 К2) дозволена
2).0 інакше
F(i,K1,K2),i>1 = sum(F(i-1,K3,K4) : ( K1 K3) (K2 K4) дозволені)
складність O(N*K^4)
Відредаговано MAXXX (2010-01-30 16:28:38)
Поза форумом
ну, woods - динамика по краю. Заводим двумерный массив a[n, i] - кол-во расстановок поля 2*N и последней маской i (i - если перегнать в K-ричную систему счисления, то мы получим две цифры - это и будут два типа деревьев). Переход от a[n] к a[n+1] - это просто сопоставление всех масок.
Вот мой код (60 баллов):
const MODULE = 2010;
var N, K : longint;
S : longint;
i, j : longint;
a, b : longint;
pool : array[1..5, 1..5] of boolean;
compare : array[0..24, 0..24] of boolean;
dyn : array[1..100, 0..25] of longint;
procedure run(cpos : longint);
var m1, m2 : longint;
begin
for m1:=0 to sqr(K)-1 do
for m2:=0 to sqr(K)-1 do
if compare[m1, m2] then
dyn[cpos, m2]:=(dyn[cpos, m2] + dyn[cpos-1, m1]) mod MODULE;
end;
begin
fillchar(pool, sizeof(pool), true);
fillchar(compare, sizeof(compare), false);
fillchar(dyn, sizeof(dyn), 0);
{read}
read(N, K);
read(S);
for i:=1 to S do begin
read(a, b);
pool[a, b]:=false;
pool[b, a]:=false;
end;
{precalc}
for i:=1 to K do
for j:=1 to K do
for a:=1 to K do
for b:=1 to K do begin
compare[(i-1)*K+j-1, (a-1)*K+b-1]:=(pool[a, b])and(pool[a, i])and(pool[b, j])and(pool[i, j]);
compare[(a-1)*K+b-1, (i-1)*K+j-1]:=compare[(i-1)*K+j-1, (a-1)*K+b-1];
end;
{running}
for i:=1 to K do
for j:=1 to K do
if pool[i, j] then
inc(dyn[1, (i-1)*K+j-1]);
for i:=2 to N do
run(i);
{write}
s:=0;
for i:=0 to sqr(K)-1 do
s:=(s+dyn[N, i]) mod MODULE;
writeln(s);
end.Поза форумом
Eol написав:
ну, woods - динамика по краю. Заводим двумерный массив a[n, i] - кол-во расстановок поля 2*N и последней маской i (i - если перегнать в K-ричную систему счисления, то мы получим две цифры - это и будут два типа деревьев). Переход от a[n] к a[n+1] - это просто сопоставление всех масок.
Можно пожалуйста ссылку где об этом методе подробно расказывается.
А то я решал через матрицы. По ресурсам получилось намного эффективнее.
Поза форумом
pilya написав:
Eol написав:
ну, woods - динамика по краю. Заводим двумерный массив a[n, i] - кол-во расстановок поля 2*N и последней маской i (i - если перегнать в K-ричную систему счисления, то мы получим две цифры - это и будут два типа деревьев). Переход от a[n] к a[n+1] - это просто сопоставление всех масок.
Можно пожалуйста ссылку где об этом методе подробно расказывается.
А то я решал через матрицы. По ресурсам получилось намного эффективнее.
На самом деле, матрицами в таких случаях не всегда выгодно делать. К примеру, если доска была бы 4*N, то динамика, описанная выше прошла бы, а решение с матрицами - вряд ли, потому что его сложность O(logN*C^3), где C - количество допустимых "профилей". Зато, если бы доска была 2*10^9, тогда наоборот, решение матрицами проходило бы, а такое - нет.
Хотя странно, что на 3 туре ограничение на размер доски всего 2*100. Мне кажется, было бы интереснее, если бы доса была 8*100 или 3*10^9. В обоих случаях описанная выше динамика не проходила бы.
Поза форумом
Задачу woods решал по аналогии с одной интересной задачей Киевской олимпиады прошлого года.
Завдання
Обчислити остачу від ділення на P кількості можливих розміщень шахових коней на дошці 4 на N, при яких вони не атакують один одного.
Вхідні дані
В єдиному рядку вхідного файлу записано два натуральних числа — довжина дошки N (2 ≤ N ≤ 109) і дільник P (2 ≤ P ≤ 109).
Вихідні дані
Єдиний рядок вихідного файлу має містити одне ціле число — остачу від ділення на P кількості можливих розміщень шахових коней на дошці 4 на N, при яких вони не атакують один одного.
Розв'язання:
Рівень 1. Можна здійснити повний перебір усіх варіантів розміщень коней з подальшою перевіркою коректності розташування. Для дошки 4×N будемо мати 2^(4N) таких розміщень. Час на перевірку коректності розташування пропорційний N. Тому таке розв’язання виконує кількість операцій, що пропорційна N∙2^N. Таким чином можна вирахувати значення кількостей для N від 2 до 7 за час туру олімпіади, задати ці кількості сталими у коді програми і для вказанихх N виводити остачу від ділення на Р попередньо обчислені кількості розташувань. Таке розв’язання набирає 15% балів.
Рівень 2. Знаючи кількість розташувань на дошці 4×(N – 1) для кожних можливих двох останніх стовпчиків, ми можемо досить швидко визначити такі кількості вже для дошки 4×N. Існує 28 варіантів розміщення коней у останніх двох стовпчиках, бо в кожній з 8 клітинок кінь може або бути або не бути. Зобразимо два останні стовпчики дошки, позначивши однаковими літерами поля літерами латиниці A, B, C, D.
A B
C D
B A
D C
Для коней, розташованих на останніх стовпчиках дошки, бити один одного можуть лише пари коней, що знаходяться у клітинках, позначених у таблиці ліворуч однією літерою. При допустимих розташуваннях для кожної з цих пар маємо 3 варіанти: або немає коней на обох клітинках, або кінь є на першій (згори), або кінь є на другій. Тому загальна кількість позицій — допустимих розташувань коней на двох останніх стовпчиках дошки — дорівнює 3^4 = 81. Для кожного такої позиції визначимо, які позиції можна отримати при коректному долученні ще одного стовпчика. Тоді для підрахунку кількості розташувань на дошці 4×N для певної позиції k додаємо кількості розташувань на дошці 4×(N – 1) для тих позицій, з яких можна перейти у k долученням стовпчика і знаходимо остачу від ділення цієї суми на P. Кількість операцій у такому алгоритмі буде пропорційна 3^8∙N, що має прийнятний час при N ≤ 10000. Таке розв’язання набирає 70% балів.
Рівень 3. Позначимо через А матрицю розміром 81×81, у якій елемент у рядку k і стовпчику j дорівнює 1, якщо з позиції j можна перейти до позиції k, та дорівнює 0, якщо такий перехід неможливий.
Позначимо через Bn матрицю розміром 81×1 (вектор-стовпчик, що має 81 координату), де значення у комірці (k ; 1) дорівнює кількості розміщень у таблиці 4×N з кінцевою позицією k. Усі координати B2 дорівнюють 1.
Маємо: А∙Bn = Bn + 1 і A^(n – 2)∙B2 = Bn при довільному натуральному n.
Кількість допустимих розташувань — це сума всіх елементів BN .
Найскладнішу частину алгоритму — підрахунок A^N – 2 — можна здій¬сни-ти за час, що пропорційний 81^3∙ logN. Для цього спочатку обчислимо матриці A, A^2, A^4, ... , A^(2s), для всіх S, при яких 2S не перевищує N – 2. Кожну з цих матриц можна вираховувати як квадрат поперед¬ньої, отже кількість операцій для вираховування кожної з них пропорційна 81^3. Далі множимо між собою ті степені матриці А, сума степенів яких дорівнює N – 2. Ці степені відповідають відмінним від нуля розрядам двійкового розкладу N – 2. Таке розв’язання набирає 100% балів.
Автор задачи: Сергей Могильный.
Відредаговано n1ce (2010-01-30 20:37:43)
Поза форумом
Вот задача Border кому интересно.
60 из 60 после исправления ошибки.
#include <iostream>
#include <math.h>
using namespace std;
#define PI 3.14159265359
//Структура для хранения окружностей
struct myStruct
{
int x;
int y;
int r;
};
//Структура для хранения окружностей которые входяят выпуклую оболочку
struct myStack
{
myStruct* p;
myStack* pNext;
};
//Функция которая получает указатели на две оружности и вычисляет угол наклона левой касательной в радианах
//также через указатель rk передается длина касательной
long double myAngle(myStruct* m1,myStruct* m2,long double *rk)
{
long long rr,x21,y21,r21;
long double x,y,rrk;
if(m1==m2) return 0;
x21=m2->x-m1->x;
y21=m2->y-m1->y;
r21=m1->r-m2->r;
rr=x21*x21+y21*y21;
rrk=sqrt((long double)(rr-r21*r21));
x=(long double)(x21*rrk+y21*r21);
y=(long double)(x21*r21-y21*rrk);
*rk=rrk;
return atan2(x,y)+PI;
}
//Добавление в очередь
myStack* AddStack(myStruct *pp, myStack *pst)
{
myStack* p;
p=new myStack;
p->p=pp;
p->pNext=NULL;
if(pst!=NULL) pst->pNext=p;
return p;
}
//Удаление очереди
void DelStack(myStack *pp)
{
myStack *p, *tp;
p=pp;
while(p!=NULL)
{
tp=p;
p=p->pNext;
delete tp;
}
}
int main(void)
{
myStruct *m;
myStack *pst,*bst;
int i,n,x,y,r;
myStruct *pLD;
long double rez;
cin>>n;
m=new myStruct[n];
pLD=m;
//чтение массива окружностей и вычисление левой нижней
for(i=0;i<n;i++)
{
cin>>x>>y>>r;
m[i].x=x;
m[i].y=y;
m[i].r=r;
if(x-r<pLD->x-pLD->r || (x-r==pLD->x-pLD->r && y<pLD->y)) pLD=&m[i];
}
//Добавление вычесленной окружности в очередь
bst=pst=AddStack(pLD,NULL);
long double dMax,dpMax,td,tdr,dr;
myStruct *pMax;
int f=1;
dpMax=2*PI;
rez=0;
//сама процедура поиска выпуклой оболочки
while(f)
{
dMax=0.0;
pMax=pst->p;
f=0;
for(i=0;i<n;i++)
{
td=myAngle(pst->p,&m[i],&tdr); // вычисление угла касательной
if(td<dpMax)// если угол меньше вычесленного для предыдущей окружности выпуклой оболочки
{
if(td>dMax)// если угол больше максимального
{
f=1;
dMax=td;
pMax=&m[i];
dr=tdr;
}
else
{
// если углы равны то проверяем данная окружнность дальше предыдущей найденой
if(td==dMax && (abs(pst->p->x-m[i].x)+abs(pst->p->y-m[i].y)-m[i].r)>(abs(pst->p->x-pMax->x)+abs(pst->p->y-pMax->y)-pMax->r))
{
f=1;
dMax=td;
pMax=&m[i];
dr=tdr;
}
}
}
}
if(f) // если удалось найти новую окружность
{
rez=rez+dr+(dpMax-dMax)*(pst->p->r+1); // добавляем длину новой касательной и длину дуги для предыдущей окружности
// кстати тут и была моя ошибка вместо радиуса предыдущей подставлял радиус текущей
// за что набрал только 10 балов :( т.е. в тех тестах что прошли окружности выпуклой оболочки имели одинаковый радиус :)
pst=AddStack(pMax,pst); // добавляем в очередь
dpMax=dMax;
}
}
rez=rez+dpMax*(pst->p->r+1); // вычисляем дугу последней окружности
pst=bst;
//*** Кому интересно можно убрать коментарии ниже и посмотреть окружности которые вошли в выпуклую оболочку
//while(pst)
//{
// cout<<pst->p->x<<','<<pst->p->y<<','<<pst->p->r<<endl;
// pst=pst->pNext;
//}
// Ну собственно и все...
cout.setf(ios::scientific,ios::floatfield);
cout.precision(13);
cout<<rez<<endl;
DelStack(bst);
delete[] m;
return 0;
}Відредаговано pilya (2010-01-31 17:29:51)
Поза форумом
Спасибо.
Кстати, вот этот код
pilya написав:
Код:
..... else { // если углы равны то проверяем данная окружнность дальше предыдущей найденой if(td==dMax && (abs(pst->p->x-m[i].x)+abs(pst->p->y-m[i].y)-m[i].r)>(abs(pst->p->x-pMax->x)+abs(pst->p->y-pMax->y)-pMax->r)) { f=1; dMax=td; pMax=&m[i]; dr=tdr; } } .....
совсем не нужен, т.к. вряд ли он будет выполняться из-за td==dMax,
в чем не трудно убедиться запустив проверку без него.
И еще. Насколько я понял, программа работает за O(N^2)? ![]()
Відредаговано Vinnie (2010-01-31 20:29:57)
Поза форумом
Просто в тестах не предусмотрено нахождение нескольких окружностей к которым можно провести общую касательную.
А скорость совершенно верно N^2.
Я пытался применить к задаче другие методы поиска выпуклой оболочки, но этот мне показался самым оптимальным. По крайней мере в этом примере надо искать только длину касательной и угол наклона, а при реализации других других алгоритмов пришлось бы выполнять дополнительные математические вычисление, например для определения как одна окружность расположена относительно двух других, что привело бы к суммарному времени не меньше данного алгоритма.
Пусть меня поправит тот кто решил эту задачу другим способом.
Поза форумом
У меня есть одна английская статья, в которой описано, как решить ее за O(NlogN), но там довольно сложный алгоритм, в котором помимо кучи вычислительной геометрии требуется ручная реализация сбалансированного двоичного дерева. Если кому интересно, могу выложить.
Поза форумом
kadr написав:
У меня есть одна английская статья, в которой описано, как решить ее за O(NlogN), но там довольно сложный алгоритм, в котором помимо кучи вычислительной геометрии требуется ручная реализация сбалансированного двоичного дерева. Если кому интересно, могу выложить.
Очень даже интересно.
Поза форумом
pilya написав:
Просто в тестах не предусмотрено нахождение нескольких окружностей к которым можно провести общую касательную.
По-моему Вам повезло
, иначе ваша программа могла бы сработать неправильно из-за сравнения td==dMax.
Смотреть например Про сравнение double
pilya написав:
А скорость совершенно верно N^2.
Я пытался применить к задаче другие методы поиска выпуклой оболочки, но этот мне показался самым оптимальным. По крайней мере в этом примере надо искать только длину касательной и угол наклона, а при реализации других других алгоритмов пришлось бы выполнять дополнительные математические вычисление, например для определения как одна окружность расположена относительно двух других, что привело бы к суммарному времени не меньше данного алгоритма.
Для определения относительного расположения окружностей Вы используете вычисление с помощью atan2 двух углов (N^2 раз). Мне кажется дешевле использовать псевдоскалярное произведение (см. Порублев, Ставровский. Алгоритмы и программы. Решение олимпиадных задач. Глава 6.).
Вашу программу можно улучшить, хотя бы исключая из дальнейшего рассмотрения уже найденные точки.
pilya написав:
Пусть меня поправит тот кто решил эту задачу другим способом.
Моя программа не набирает 60 баллов, поэтому поправлять не буду ![]()
Відредаговано Vinnie (2010-02-01 08:51:23)
Поза форумом
помоему вы не прониклись задачей
одна окружность может участвовать в выпуклой оболочке максимум до 4 раз поэтому исключать окружности из рассмотрения нельзя.
Поза форумом
pilya написав:
помоему вы не прониклись задачей
одна окружность может участвовать в выпуклой оболочке максимум до 4 раз поэтому исключать окружности из рассмотрения нельзя.
Почему только до 4? Представьте себе одну большую окружность, а вокруг нее равномерно распределены 5 маленьких, причем они лежат очень близко к границе большой. Тогда большая окружность даст 5 дуг в выпуклую оболочку. Если увеличить количество маленьких, то будет еще больше.
P.S.: Вот ссылка на ту статью, о которой я говорил выше.
Поза форумом
согласен с 4-мя погорячился ![]()
Спасибо за статью.
Поза форумом
Vinnie написав:
По-моему Вам повезло
, иначе ваша программа могла бы сработать неправильно из-за сравнения td==dMax.
Смотреть например Про сравнение double
Вопервых мне не повезло потому что я сдела другую ошибку, которую указал в коментариях ![]()
А во вторых не зыбывайте что коодинаты окружностей целые числа и поэтому функция вполне может вернуть два абсолютно одинаковых угла для этого и делается сравнение.
Vinnie написав:
Для определения относительного расположения окружностей Вы используете вычисление с помощью atan2 двух углов (N^2 раз). Мне кажется дешевле использовать псевдоскалярное произведение (см. Порублев, Ставровский. Алгоритмы и программы. Решение олимпиадных задач. Глава 6.).
Во первых atan2 используется не для нахождения взаимного расположения окружностей, а для определения угла касательной в радианах (хотя это вы могли прочитать и в коментариях). А псевдоскалярное произведение для определения взаимного расположения трех точек а не окружностей разного диаметра.
Vinnie написав:
Вашу программу можно улучшить, хотя бы исключая из дальнейшего рассмотрения уже найденные точки.
А теперь повторю, так как с утра отвечал с мобильного телефона.
Даже найденую окружность нельзя исключать из расмотрения потому что она может несколько раз входить в выпуклую оболочку.
P.S.Ваша ошибка слово точки, а задача про геометрическое место точек, находящихся на равном растоянии от точки. ![]()
Відредаговано pilya (2010-02-01 19:35:31)
Поза форумом
pilya написав:
Просто в тестах не предусмотрено нахождение нескольких окружностей к которым можно провести общую касательную.
В задачі взагалі вимагається не "нахождение окружностей", а знаходження мінімально можливої довжини огорожі. Якщо мова йде про те, що в тестах взагалі нема випадку кількох (строго більше двох) кіл зі спільною дотичною -- взагалі-то такі тести є. Але, можливо, й варто було продумати їх якось детальніше.
Проблема ж створюється не просто фактом наявності кількох кіл зі спільною дотичною, а тим, що вони водночас і мають спільну дотичну, і розглядаються в "незручному" порядку. А який порядок для якої програми буде "незручним" -- продумати наперед важко.
Відредаговано Ilya Porublyov (2010-02-02 12:23:32)
Поза форумом
Полностью с Вами согласен для этого и делалась проверка на окружность самую удаленную из всех что имеют общую касательную
Поза форумом