Bài toán: Tìm các số đặc biệt của dãy A cho trước

Thuật giải : Gọi K,F[I],G[I} lần lượt là độ dài của dãy tăng dài nhất,dãy tăng dài nhất kết thúc tại A[I],dãy tăng dài nhất bắt đầu từ A[I].Như vậy A[I] là một số đặc biệt khi và chỉ khi F[I]+G[I]=K+1.Do đó bài tóan đã được đưa về dạng quy họach động cơ bản thường thấy là tìm dãy con tăng dài nhất.Cách giải thông thường với lọai bài này có độ phức tạp N 2 ,dĩ nhiên không thể áp dụng ở đây do N quá lớn (≤ 10 5 ).Vì vậy ta cần phải hướng tới một thuật giải khác có độ phức tạp nhỏ hơn,ở đây xin giới thiệu với bạn đọc phương pháp tìm dãy con tăng dài nhất với độ phức tạp NlogN,bộ nhớ tỷ lệ với N:

• Gọi F[I] là độ dài dãy tăng dài nhất kết thúc tại I,S[I] là giá trị nhỏ nhất trong số các phần tử kết thúc của các dãy tăng có độ dài I.

• Tại mỗi thời điểm I:lưu giữ K là độ dài của dãy con tăng dài nhất tới thới điểm đó.Tìm J max sao cho S[J]

• F[I]:=J+1.

 

doc4 trang | Chia sẻ: lethuong715 | Lượt xem: 498 | Lượt tải: 0download
Bạn đang xem nội dung tài liệu Bài toán: Tìm các số đặc biệt của dãy A cho trước, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Bài toán: Tìm các số đặc biệt của dãy A cho trước
Bài toán : Cho dãy số nguyên A[1],A[2],,A[N] khác nhau đôi một (N<=10 5 ,1<=A[I]<=N).A[I] được gọi là một số đặc biệt đối với dãy số trên nếu A[I] thuộc ít nhất một dãy con tăng dài nhất của A.Ở đây xin nhắc lại một chút về định nghỉa dãy con tăng dài nhất,dãy con tăng dài nhất là dãy A[i 1 ],A[i 2 ],,A[ip] thỏa: 
• 1 ≤ i 1 < i 2 < < ip ≤ N. 
• A[i 1 ] < A[i 2 } <  < A[ip]. 
• P lớn nhất có thể được. 
Yêu cầu của bài toán là bạn phải chỉ ra tất cả các số đặc biệt của dãy A theo định nghĩa ở trên. 
Input : Dữ liệu vào từ file SUPERNUM.INP : 
•  Dòng đầu là số T (1 ≤ T ≤ 10) là số bộ test bạn phải giải quyết. 
•  T nhóm dòng sau,mỗi nhóm gồm 2 dòng: 
•  Dòng đầu là số N. 
•  Dòng thứ 2 chứa N số nguyên từ 1 tới N. 
Output : Dữ liệu ra ghi lên file SUPERNUM.OUT gồm T dòng,mỗi dòng ghi các số đặc biệt của bộ test tương ứng theo thứ tự tăng dần. 
SUPERNUM.INP 
SUPERNUM.OUT 
2 
7 
1 2 3 7 4 5 6 
5 
1 4 3 2 5 
6 
1 2 3 4 5 6 
5 
1 2 3 4 5 
Lưu ý:Bài tóan này có thể sử dụng Free Pascal để giải quyết . 
Thuật giải : Gọi K,F[I],G[I} lần lượt là độ dài của dãy tăng dài nhất,dãy tăng dài nhất kết thúc tại A[I],dãy tăng dài nhất bắt đầu từ A[I].Như vậy A[I] là một số đặc biệt khi và chỉ khi F[I]+G[I]=K+1.Do đó bài tóan đã được đưa về dạng quy họach động cơ bản thường thấy là tìm dãy con tăng dài nhất.Cách giải thông thường với lọai bài này có độ phức tạp N 2 ,dĩ nhiên không thể áp dụng ở đây do N quá lớn (≤ 10 5 ).Vì vậy ta cần phải hướng tới một thuật giải khác có độ phức tạp nhỏ hơn,ở đây xin giới thiệu với bạn đọc phương pháp tìm dãy con tăng dài nhất với độ phức tạp NlogN,bộ nhớ tỷ lệ với N: 
•  Gọi F[I] là độ dài dãy tăng dài nhất kết thúc tại I,S[I] là giá trị nhỏ nhất trong số các phần tử kết thúc của các dãy tăng có độ dài I. 
•  Tại mỗi thời điểm I:lưu giữ K là độ dài của dãy con tăng dài nhất tới thới điểm đó.Tìm J max sao cho S[J]<A[I] khi đó : 
•  F[I]:=J+1. 
•  Nếu S[F[I]]>A[I] thì S[F[I]]:=A[I]. 
•  Nếu F[I]>K thì K:=F[I]. 
•  Với cách tính như trên dễ thấy tại mỗi thời điểm dãy S là dãy tăng : S[1]<S[2]<.<S[I] (có thể chứng minh bằng quy nạp ).Điều này có nghĩa là mỗi lần tính J ta chỉ phải tốn thời gian tỷ lệ với logN,do đó độ phức tạp của thuật tóan chỉ là NlogN. 
Source Code : Sau đây là chương trình được cài đặt theo tư tưởng ở trên (chạy trên Free Pascal ): 
{ ------------------------------------------------------------ } 
Const input='supernum.inp'; 
output='supernum.out'; 
maxn=10000; 
Var f,g:text; 
n,test,t,l,kmax:longint; 
a,incs,decs,s:array[1..maxn] of longint; 
Function Find(x:longint):longint; 
Var tmax,left,right,mid:longint; 
Begin 
left:=1;right:=kmax;tmax:=0; 
Repeat 
mid:=(left+right) shr 1; 
If s[mid]>a[x] then right:=mid-1 else 
If s[mid]<a[x] then 
Begin 
left:=mid+1; 
tmax:=mid; 
End; 
Until left>right; 
Find:=tmax; 
End; 
Procedure SolveProblem; 
Var i,t,longest,dem:longint; 
Begin 
incs[1]:=1;s[1]:=a[1];kmax:=1;a[1]:=-a[1]; 
For i:=2 to n do 
Begin 
t:=Find(i); 
incs[i]:=t+1; 
If incs[i]>kmax then 
Begin 
kmax:=incs[i]; 
s[kmax]:=a[i]; 
End 
Else If s[incs[i]]>a[i] then s[incs[i]]:=a[i]; 
a[i]:=-a[i]; 
End; 
decs[n]:=1;s[1]:=a[n];kmax:=1; 
longest:=decs[n]+incs[n];dem:=0; 
For i:=n-1 downto 1 do 
Begin 
t:=Find(i); 
decs[i]:=t+1; 
If decs[i]>kmax then 
Begin 
kmax:=decs[i]; 
s[kmax]:=a[i]; 
End 
Else If s[decs[i]]>a[i] then s[decs[i]]:=a[i]; 
If longest<decs[i]+incs[i] then longest:=decs[i]+incs[i]; 
End; 
Fillchar(s,sizeof(s),0); 
For i:=1 to n do 
If (incs[i]+decs[i])=longest then 
Begin 
Inc(dem); 
s[-a[i]]:=1; 
End; 
Writeln(g,dem); 
For i:=1 to n do 
If s[i]=1 then Write(g,i,' '); 
Writeln(g); 
End; 
Begin 
Assign(f,input);Reset(f); 
Assign(g,output);Rewrite(g); 
Readln(f,test); 
For t:=1 to test do 
Begin 
Readln(f,n); 
For l:=1 to n do 
Read(f,a[l]); 
SolveProblem; 
End; 
Close(f);Close(g); 
End. 

File đính kèm:

  • docBài toan tim cac so dac biet cua day A cho truoc.doc