Контакт
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; }