На форумі обговорюються лише питання, пов'язані з олімпіадою
Ви не зайшли.
Задача Unizero.
Припустимо, що у нас є поле 00...00 (довжиною n). І за умовою задачі нам потрібно розтавити одиниці (більш ніж одну) так, щоб не суперечило даній умові. Випадки розміщення будуть наступні: 
1) Через один нуль (00..01010..000): щоб не порушити умову, будем розтавляти такі послідовності, як: 101, 10101,1010101 і т.д. Щоб знайти кількість позицій для кожної такої послідновності в нашому полі, потрібно до загальної суми додати різницю довжини поля і дожину вибраної послідовності + 1. Для кращого розуміння розглянемо поле довжиною 6 (000000). Кількість позицій довжиною в 3 (101) = 6 - 3 + 1 (позиції: 101000, 010100,001010,000101), довжиною в 5 (10101) = 6-5+1 (101010, 010101). Отже відповідь для послідовностей "через один нуль" буде : (n-2)+(n-4)+(n-6)... .
2) Через к нулів (00..0100..{k}..0010..00). Порядок обчислення буде аналогічний прикладу через один нуль, а саме сума = (n-(k)+1)+(n-(2*k)+1)+(n-(3*k)+1)...
Замітимо, що коли будемо підраховувати загальну суму усіх (n-i+1), даний вираз (n-i+1), де 1<i<n, буде зустрічатися рівно числу кільності дільників числа i.
Отже, для знаходження відповіді на поставлену задачу, потрібно підрахувати суму( (n-i)*(кількість_дільників(i)) ).
Код вийшов наступний:
for(int i=2;i<n;i++)
        for(int j=i;j<n;j+=i)
            a[j]++;
    ll sm = 0;
    for(int i=2;i<n;i++)
    sm+=a[i]*(n-i);
    cout<<sm;
Напевно це рішення не є подібним авторському, але ,не знаю чому, дане рішення бере нуль балів (Time limit), хоча відправка після завершення 2 туру показала, що мінімальний час виконання: 
(0.06 c - 0.07 c) - і це 19 тестів, 20 тест - 0,1 с, і остальні по 0,52 с.
Чесно кажучи, не розумію таку систему оцінювання 
Відредаговано PAS99 (2015-12-22 10:47:40)
Поза форумом
Задача Unizero.
Ніби все добре але проходить 26 з 40. Допоможіть, не знаю в чому пробема.
ПС. Тормозить на більших тестах
var k,l:int64;
procedure func(k,i,r:int64; var l:int64);
var b,a,n:int64;
begin
 b:=k-2*i;
 a:= b mod i;
 n:=1+b div i;
 if(b>0) then func(k, i+1, r+(a+b)*n div 2,l) else l:=r;
end;
begin
 readln(k);
 func(k,1,0,l);
 writeln(l);
end.
Поза форумом
PAS99 написав:
Задача Unizero.
Припустимо, що у нас є поле 00...00 (довжиною n). І за умовою задачі нам потрібно розтавити одиниці (більш ніж одну) так, щоб не суперечило даній умові. Випадки розміщення будуть наступні:
1) Через один нуль (00..01010..000): щоб не порушити умову, будем розтавляти такі послідовності, як: 101, 10101,1010101 і т.д. Щоб знайти кількість позицій для кожної такої послідновності в нашому полі, потрібно до загальної суми додати різницю довжини поля і дожину вибраної послідовності + 1. Для кращого розуміння розглянемо поле довжиною 6 (000000). Кількість позицій довжиною в 3 (101) = 6 - 3 + 1 (позиції: 101000, 010100,001010,000101), довжиною в 5 (10101) = 6-5+1 (101010, 010101). Отже відповідь для послідовностей "через один нуль" буде : (n-2)+(n-4)+(n-6)... .
2) Через к нулів (00..0100..{k}..0010..00). Порядок обчислення буде аналогічний прикладу через один нуль, а саме сума = (n-(k)+1)+(n-(2*k)+1)+(n-(3*k)+1)...
Замітимо, що коли будемо підраховувати загальну суму усіх (n-i+1), даний вираз (n-i+1), де 1<i<n, буде зустрічатися рівно числу кільності дільників числа i.
Отже, для знаходження відповіді на поставлену задачу, потрібно підрахувати суму( (n-i)*(кількість_дільників(i)) ).
Код вийшов наступний:
for(int i=2;i<n;i++)
for(int j=i;j<n;j+=i)
a[j]++;
ll sm = 0;
for(int i=2;i<n;i++)
sm+=a[i]*(n-i);
cout<<sm;
Напевно це рішення не є подібним авторському, але ,не знаю чому, дане рішення бере нуль балів (Time limit), хоча відправка після завершення 2 туру показала, що мінімальний час виконання:
(0.06 c - 0.07 c) - і це 19 тестів, 20 тест - 0,1 с, і остальні по 0,52 с.
Чесно кажучи, не розумію таку систему оцінювання
Из вашего разбора уже видно, что нужно посчитать сумму арифметических прогрессий с шагом - 2, 3 и т.д. Поскольку сумма АП считается за О(1). То такое решение не превосходило бы О(n).
Поза форумом
Я розумію, що рішення не ідеальне, але проходячи 80% тестів не більше, ніж за 0,1 с , воно б мало набирати "хоч щось" 
Поза форумом
На всякий случай приведу полнобальные решения (они отличаются от того, что я посылал на тур):
Unizero
#include <iostream>
int main()
{
    long long n,c,i,ans=0;
    std::cin>>n;
    for(i=2;i<n;++i)
    {
        c=(n+i-1)/i;
        ans+=n*(c-1)-i*c*(c-1)/2;
    }
    std::cout<<ans;
    return 0;
}Идея: формула решения , внутренняя сумма раскрыта для ускорения вычислений. Желающие могут попробовать раскрыть и внешнюю сумму.
Сложность: O(n) времени, O(1) памяти.
Walk
#include <cstdio>
long long egcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=a<0?-1:+1;
        y=0;
        return a<0?-a:a;
    }
    long long c=a/b;
    long long p,q;
    long long ret=egcd(b,a%b,p,q);
    x=q;
    y=p-c*q;
    return ret;
}
long long inv_m(long long a,long long b)
{
    long long x,y;
    egcd(a,b,x,y);
    return ((x%b)+b)%b;
}
long long a(long long n)
{
    const long long m=1000000007LL;
    long long ret=0;
    long long c=1;
    for(long long i=0;i<n+1;++i)
    {
        ret=(ret+c)%m;
        c=(((c*2*(2*i+1))%m)*inv_m(i+2,m))%m;
    }
    return ret;
}
int main()
{
    long t;
    scanf("%ld",&t);
    printf("%ld",(long)a(((long long)t-1LL)/2LL));
    return 0;
}Идея: беглый взгляд на OEIS находит выражение для ответа через сумму чисел Каталана. Для чисел Каталана есть рекуррентная формула, поэтому (частичная) сумма и следующее число Каталана считаются вместе. Формула содержит деление, но т. к. 1000000007 - простое число, то мы имеем право "делить по модулю", т. е. умножать на обратное по модулю 1000000007.
Сложность: O(t) времени, O(1) памяти.
Hanoy2015
#include <iostream>
#include <algorithm>
int main()
{
    int N;
    int a[64];
    int c=0;
    unsigned long long answer=0;
    std::cin>>N;
    for(int i=0;i<N;++i)
        std::cin>>a[i];
    std::sort(a,a+N);
    for(int i=N-1;i>=0;--i)
        answer+=1LL<<(c+=(i<N-1&&a[i]!=a[i+1]));
    std::cout<<answer;
    return 0;
}Идея: сортируем диски, дальше - обычные Ханойские башни, но стопка из k одинаковых дисков воспринимается как 1 диск со стоимостью перемещения в k ходов.
Сложность: O(N) времени, O(1) памяти.
Schoolnet2015n
#include <cstdio>
static const int MAX_N=1000;
bool n[MAX_N][MAX_N]={{0}};
int c[MAX_N]={0};
int s[MAX_N]={0};
int N;
int dfs(int i)
{
    int ret=1;
    if(c[i]) return 0;
    c[i]=1;
    for(int j=0;j<N;++j)
        if(n[i][j])
            ret+=dfs(j);
    return ret;
}
int main()
{
    int a,b=0,c;
    scanf("%d",&N);
    for(int i=0;i<N;++i)
        for(int j=0;j<N;++j)
        {
            scanf("%d",&a);
            n[i][j]=a;
        }
    for(int i=0;i<N;++i)
    {
        if((a=dfs(i))>b)
        {
            b=a;
            c=i+1;
        }
    }
    printf("%d %d",b,c);
    return 0;
}Идея: стандартная задача.
Сложность: O(N^2) времени, O(N^2) памяти.
FactZero
#include <cstdio>
int main()
{
    long n,k;
    long m=0;
    long p[32]={};
    long c[32]={};
    long b=2000000000L;
    scanf("%ld%ld",&n,&k);
    for(long d=2,t=k;t>1;++d)
    {
        if(t%d==0)
        {
            while(t%d==0)
            {
                ++c[m];
                t/=d;
            }
            p[m++]=d;
        }
    }
    for(int i=0;i<m;++i)
    {
        long q=n;
        long t=0;
        while(q>0) {q/=p[i];t+=q;}
        t/=c[i];
        if(t<b) b=t;
    }
    printf("%ld\n",b);
    return 0;
}Идея: раскладываем k на простые множители, смотрим, с какой кратностью каждый множитель входит в n!. Ищем минимум (с учётом кратностей в k).
Сложность: O(k+log(n)*log(k)) времени, O(log(k)) памяти.
Правка: временная сложность в FactZero.
Відредаговано FordPerfect (2016-01-12 17:50:45)
Поза форумом
FordPerfect, дякую за надані рішення. Вважаю дуже корисним для зацікавлених учасників ознайомлення з рішеннями саме після закінчення туру, коли умови задач іще "крутяться" в голові.
Поза форумом
Hanoy2015
Важко конкурувати з лаконічністю рядка 
answer+=1LL<<(c+=(i<N-1&&a[i]!=a[i+1]));
в рішенні FordPerfect, але насмілюсь викласти і своє повнобальне рішення.
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
   int N, a, n[10001]={};
    cin >> N;
    for (int i=1; i<=N; i++)
        {
            cin>>a;
            n[a]++;
        }
long double res=0;
for (int i=10000,k=0; i>0; i--)
{
    if (n[i]!=0)
    {
        res+=pow(2.0,k)*n[i];
        k++;
    }
}
cout << (unsigned long long)res;
return 0;
}Алгоритм такий:
В класичному варіанті кількість перекладань дорівнює: 2^n -1
Якщо перекладати диски пачками, то так воно і буде (n – кількість «пачок»).
Але кожна пачка перекладається поштучно, тобто найбільші диски перекладаються один раз (2^0*а), де а-кількість найбільших дисків, далі 2^1*в, де в – кількість менших дисків, далі 2^2*с, де с – кількість ще менших дисків і т.д.
1) Підраховуємо яких і скільки дисків є за допомогою додаткового масиву n[10000] під час уведення.
2) Потім знайдемо суму перекладань.
Обрахунки виконуємо в дійсних числх, а результат виводимо в максимально можливому типі цілих.
Відредаговано LVV (2015-12-24 06:31:12)
Поза форумом
Кстати в строчке
answer+=1LL<<(c+=(i<N-1&&a[i]!=a[i+1]));
всё-таки нет undefined behavior, а только implementation-defined. Но, всё-равно, лучше, наверное:
answer+=1ULL<<(c+=(i<N-1&&a[i]!=a[i+1]));
Поза форумом
код розвязку задачі Unizero на основі знаходження сум арифметичних прогресій:
var l,f:int64;
n,i,j,k,nach:longint;
begin
read(n);
n:=n-2;l:=0;k:=1;
while (n>0)do begin
   if k=1 then begin
                   f:=n;
                   nach:=1;
                   end else begin
                      nach:=n mod k;
                       if nach=0 then nach:=k;
                      f:=(n-nach)div k+1;
                   end;
   l:=l+(nach+n)*f div 2;
   n:=n-2;k:=k+1;
end;
writeln(l);
end.протокол тестування:
Тест    Результат    Час роботи
00    PASSED (+0)    0.01 с
01    PASSED (+1)    0.01 с
02    PASSED (+1)    0.01 с
03    PASSED (+1)    0.01 с
04    PASSED (+1)    0.01 с
05    PASSED (+1)    0.01 с
06    PASSED (+1)    0.01 с
07    PASSED (+1)    0.01 с
08    PASSED (+1)    0.01 с
09    PASSED (+1)    0.01 с
10    PASSED (+1)    0.01 с
11    PASSED (+2)    0.01 с
12    PASSED (+2)    0.01 с
13    PASSED (+2)    0.01 с
14    PASSED (+2)    0.01 с
15    PASSED (+2)    0.01 с
16    PASSED (+2)    0.01 с
17    PASSED (+2)    0.01 с
18    PASSED (+2)    0.01 с
19    PASSED (+2)    0.02 с
20    PASSED (+2)    0.04 с
21    PASSED (+2)    0.04 с
22    PASSED (+2)    0.09 с
23    PASSED (+2)    0.10 с
24    PASSED (+2)    0.14 с
25    PASSED (+2)    0.17 с
Поза форумом
Unizero, праздник продолжается:
#include <iostream>
// sum[i=1;n] floor(n/i)
long long s1(long long n)
{
    long long ret=0;
    long long i=1;
    for(i=1;i*i<=n;++i)
        ret+=2*(n/i);
    --i;
    ret-=i*i;
    return ret;
}
// sum[i=1;n] floor(n/i)*i
 long long s2( long long n)
{
     long long ret=0;
     long long i=1;
    for(i=1;i*i<=n;++i)
    {
        long long a=n/(i+1);
        long long b=n/i;
        ret+=b*i;
        if(i<b) ret+=i*(b*(b+1)-a*(a+1))/2;
    }
    return ret;
}
// sum[i=1;n] floor(n/i)^2*i
long long s3(long long n)
{
    long long ret=0;
    long long i=1;
    for(i=1;i*i<=n;++i)
    {
        long long a=n/(i+1);
        long long b=n/i;
        ret+=b*b*i;
        if(i<b) ret+=i*i*(b*(b+1)-a*(a+1))/2;
    }
    return ret;
}
int main()
{
    long long n;
    std::cin>>n;
    std::cout<<n*s1(n-1)-(s3(n-1)+s2(n-1))/2-n*(n-1)/2;
    return 0;
}Сложность: O(sqrt(n)) времени, O(1) памяти.
Идея: можно воспользоваться формулой из http://math.stackexchange.com/questions … rogression и обобщить её следующим образом:
(правка: исправил формулу)
Версии для ceil легко получить, используя тот факт, что ceil(n/i)=floor((n+i-1)/i)=floor((n-1)/i)+1.
Таким образом, формула из поста #6 может быть выражена через приведённые выше суммы.
Відредаговано FordPerfect (2016-01-17 06:47:10)
Поза форумом