Контакт
http://acm.pku.edu.cn/JudgeOnline/problem?id=1174

   Доктор Астро Ински (Astro Insky) работает в радиотелескопическом центре. Недавно она заметила очень странное пульсирующее микроволновое излучение, исходящее непосредственно из центра галактики. Посланы ли эти сигналы какой-нибудь внеземной формой разумной жизни? Или это простое сердцебиение звезд?

   Вы должны помочь доктору Ински отыскать истину, создав инструмент для анализа битовых последовательностей в записанных ею сообщениях. Доктор Ински хочет найти битовые подпоследовательности длиной от А до В включительно, которые встречаются в записанной последовательности наиболее часто. Подпоследовательности могут перекрываться. Определяются N наибольших различных частот (т.е. количество вхождений). Учитываются подпоследовательности, которые встречаются хотя бы один раз.

   Входные данные

   Стандартный вход содержит данные в следующем формате:
   В первой строке находится число А - минимальная длина подпоследовательности.
   Во второй строке находится число В - максимальная длина подпоследовательности.
   В третьей строке задано число N - количество различных частот вхождения.
   В четвертой задано саму полученную последовательность, состоящую из символов 0 и 1, символ 2 - признак окончания сообщения.

   Размер входных данных не превышает 2 Мбайта. Параметры A, B и N имеют такие ограничения:
   0 < N <= 20
   0 < A <= B <= 12.

   Выходные данные

   Вы должны вывести не более N строк, каждая из которых содержит одну из N наибольших частот вхождения и соответствующие ей подпоследовательности. Строки должны располагаться в порядке убывания частот вхождения и иметь следующий вид:

    частота подпоследовательность подпоследовательность ... подпоследовательность.

   Частота - это количество вхождений указанных далее подпоследовательностей. Подпоследовательности в каждой строке должны располагаться в порядке убывания длины. Подпоследовательности одинаковой длины должны располагаться в порядке убывания их числового значения. Если в последовательности встречается менее N различных частот, то выходные данные будут содержать менее N строк
   
   Пример входных данных

2
4
10
010100100100010001111011000010100110011110000100100111100100000002

   Пример выходных данных

23 00
15 10 01
12 100
11 001 000 11
10 010
8 0100
7 1001 0010
6 0000 111
5 1000 110 011
4 1100 0011 0001

   Анализ условия и разбор идеи решения

   Пример решения на Pascal:

Код:
program Contact;
const MAXPAT = 16;
      SIZE   = 2*4096;
type  Pair =
	    record
	      index:integer;
	      val:Longint;
	    end;
      TMap =array[0..SIZE-1] of Pair;
var table:TMap;
    MSK  :array[0..MAXPAT] of Word;
procedure InitPatternTable;
var i,p:word;
begin
  p := 0;
  for i:=0 to MAXPAT-1 do
    begin
      p := p shl 1;
      p := p or 1;
      MSK[i]:=p;
    end;
  for i:=0 to SIZE-1 do
    begin
      table[i].index:=i;
      table[i].val:=0;
    end;
end;

procedure PrintPattern(var i:integer);
var s:array[0..MAXPAT-1] of char;
    j,l:integer;
begin
  for j:=1 to MAXPAT-1 do
    begin
      l := MAXPAT-(j+1);
      if (i and 1)<>0 then
	s[l]:='1'
      else s[l]:='0';
      i:= i shr 1;
    end;
  j := 0;
  while(s[j]<>'1') do inc(j);
  inc(j); (* remove leading 1 *)
  while(j<MAXPAT-1) do
    begin
      write(s[j]);
      inc(j)
    end;
end;

function LT(a,b:Pair):boolean;
begin
  if(a.val = b.val) then
     LT := a.index < b.index
    else LT := a.val < b.val
end;

procedure Quicksort(loBound	: integer ;
    hiBound	: integer );
var loSwap, hiSwap: integer;
    pivot, temp: Pair;
begin
   if (loBound >= hiBound) then (* Zero or one item to sort *)
      exit;
   if (hiBound-loBound = 1) then
      begin (* Two items to sort *)
        if LT(table[loBound] ,table[hiBound]) then
	   begin
	      temp := table[loBound];
	      table[loBound] := table[hiBound];
	      table[hiBound] := temp;
	   end;
        exit;
      end;
   pivot := table[(loBound+hiBound) div 2]; (* 3 or more items to sort *)
   table[(loBound+hiBound) div 2] := table[loBound];
   table[loBound] := pivot;
   loSwap := loBound + 1;
   hiSwap := hiBound;
   repeat
      while (loSwap <= hiSwap) and NOT LT(table[loSwap],pivot)
	 do inc(loSwap);
      while LT(table[hiSwap],pivot)
	 do dec(hiSwap);
      if (loSwap < hiSwap) then
      begin
	 temp := table[loSwap];
	 table[loSwap] := table[hiSwap];
	 table[hiSwap] := temp;
      end;
   until (loSwap >= hiSwap);
   table[loBound] := table[hiSwap];
   table[hiSwap] := pivot;
   Quicksort(loBound, hiSwap-1);
   Quicksort(hiSwap+1, hiBound);
end; (* Quicksort *)

procedure MakeListing(M:integer; L:integer;N:integer);
label done;
var T,i,lm:integer;
    c:LongInt;
begin
  T := MSK[L]+1;
  QuickSort(MSK[M-1]+1,MSK[L]);
  i:=MSK[M-1]+1;
  lm:=0;
  while (lm<N) and (table[i].val<>0) do
    begin
      c := table[i].val;
      write(c,' ');
      while table[i].val = c  do
	begin
	  PrintPattern(table[i].index);
	  inc(i);
	  if table[i].val = c then
	    write(' ')
	  else writeln;
	  if i=T then goto done;
	end;
    inc(lm);
    end;
  done:;
end;

procedure ProcessFile(var M:integer; L:integer; T:integer);
var i,mask,p,mu,pp,li:word;
    ch:char;
    b:longInt;
    goon:boolean;
begin
  p := 0;
  b := 0;

  { Set the bitmask for pattern length }

  mask := MSK[L+1];

  { Init with first M bits }
  while b<M do
    begin
      read(ch);
      inc(b);
      p := p shl 1;
      if ch='1'
	then p := p or 1;
    end;
  { b = M }
  { update "first" table position }
  mu := MSK[M-1];
  pp := mu+1+(p and mu);
  table[pp].val:=1;
  goon := true;
  while goon do
    begin
      read(ch);
      if ch='2' then goon := false
      else
        begin
          inc(b);
          { update current pattern }
          p := p shl 1;
          if ch = '1' then p := p or 1;
          p := p and mask;
          if b <= L then li := b else li := L;
          { update all preceeding table positions }
          for i:=M-1 to li-1 do
            begin
              mu := MSK[i];
              pp := mu+1+(p and mu);
              inc(table[pp].val);
            end;
        end;
    end;
end;

procedure Scan;
var M,L,T : integer;
        f : text;
begin
  InitPatternTable;
  readln(M);
  readln(L);
  readln(T);
  ProcessFile(M,L,T);
  MakeListing(M,L,T);
end;

begin
  Scan;
end.

Пример решения на GnuC++

Код:
#include <iostream>
#include <cstdio> 
#include <algorithm>
using namespace std;  
const int MaxLen = 2010000;  
char str[MaxLen];  
int N,A,B,Len,cnt;  
int Arr[100000];  
typedef struct re{  
     int num,len,time;  
}re;  
bool operator <(const re& a,const re& b){  
     if(a.time > b.time) return true;  
     if(a.time == b.time){  
         if(a.len  > b.len) return true;  
         else if(a.len == b.len){  
             if(a.num > b.num) return true;  
             else return false;  
         }else return false;  
     }else return false;  
}  
re R[100000];  
int input(){  
     scanf("%d%d",&A,&B);  
     scanf("%d",&N);  
     getchar();  
     char tmp;  
     int i = 0 ;  
     while(tmp = getchar()){  
         if(tmp == '2') break;  
         else str[i++] = tmp;  
     }  
     return i;  
}  
int Insert(char* s,int len){  
     int i = 1;  
     for(int j = 0 ;j < len; ++j){  
         if(s[j] == '0')  
             i <<=1;  
         else i = (i << 1) + 1;  
     }  
     ++Arr[i];  
}  
void work(){  
     for(int i = A; i <= B; ++i)  
         for(int j = 0 ;j <= Len - i; ++j)  
             Insert(str + j,i);  
}  
void print(int num,int len){  
     char tmp[20];  
     int t = 0;  
     while(t < len){  
         if(num & 1) tmp[len - t-1] = '1';  
         else tmp[len - t -1] = '0';  
         ++t;  
         num >>=1;  
     }  
     for(int i = 0 ;i <len; ++i)  
         putchar(tmp[i]);  
     putchar(' ');  
}  
void calc(){  
     int down = (1 << A);  
     int up = (1 << ( B + 1));  
     for(int len = A; len <= B; ++len){  
         for(int i = (1 << len);i < (1<<(len+1)); ++i){  
             if(Arr[i] != 0){  
                 R[cnt].num = i; R[cnt].len = len; R[cnt].time = Arr[i];  
                 ++cnt;  
             }  
         }  
     }  
}  
int main(){  
     Len = input();  
     work();  
     calc();  
     sort(R,R+cnt);  
     int ccc = 0 ;  
     int i = 0;  
     while(i < cnt && ccc < N){  
         int ttt = R[i].time;  
         printf("%d ",R[i].time);  
         while(R[i].time == ttt){  
             print(R[i].num,R[i].len);  
             ++i;  
         }  
         putchar('\n');  
         ++ccc;  
     }  
     return 0;  
}