LCS2X spoj VOI2014 – Dãy con chung bội hai dài nhất

Nguồn đề bài http://vn.spoj.com/problems/LCS2X/

1. Đề bài LCS2X spoj

Dãy C = c1, c2, .. ck được gọi là dãy con của dãy A = a1, a2, .., an nếu C có thể nhận được bằng cách xóa bớt một số phần tử của dãy A và giữ nguyên thứ tự của các phần tử còn lại, nghĩa là tìm được dãy các chỉ số 1 ≤ l1 < l2 < … < lk ≤ n sao cho c1 = a_l1, c2 = a_l2, …, ck = a_lk. Ta gọi độ dài của dãy là số phần tử của dãy.

Cho hai dãy A = a1, a2, …, am và B = b1, b2, …, bn Dãy C = c1, c2, …, ck được gọi là dãy con chung bội hai của dãy A và B nếu C vừa là dãy con của dãy A, vừa là dãy con của dãy B và thỏa mãn điều kiện 2 × ci ≤ c(i+1) (i = 1, 2, …, k – 1).

Yêu cầu

Cho hai dãy A và B. Hãy tìm độ dài dãy con chung bội hai có độ dài lớn nhất của hai dãy A và B.

Input

Dòng đầu tiên chứa T là số lượng bộ dữ liệu. Tiếp đến là T nhóm dòng, mỗi nhóm cho thông tin về một bộ dữ liệu theo khuôn dạng sau:

  • Dòng đầu chứa 2 số nguyên dương m và n.
  • Dòng thứ hai chứa m số nguyên không âm a1, a2, …, am mỗi số không vượt quá 10^9.
  • Dòng thứ ba chứa n số nguyên không âm b1, b2, …, bn mỗi số không vượt quá 10^9.
  • Các số trên cùng một dòng được ghi cách nhau ít nhất một dấu cách.

Giới hạn

  • 30% số test có m, n <= 15.
  • 30% số test khác có m, n <= 150.
  • có 40% số test còn lại có m, n <= 1500.

Output

Ghi ra T dòng, mỗi dòng ghi một số nguyên là độ dài dãy con chung bội hai dài nhất của dãy A và B tương ứng với bộ dữ liệu vào.

Example

Input:
1
5 5
5 1 6 10 20
1 8 6 10 20

Output:
3

2. Hướng dẫn LCS2X spoj

Gọi F[i, j] là độ dài dãy con chung dài nhất của dãy A[1..i] và dãy B[1..j] thỏa điều kiện đề bài và A[i]=B[j].

Công thức truy hồi:

  • Nếu A[i]<>B[j] thì  F[i, j]=0
  • F[i, j]= Max{F[u, v]/ u<i, v<j}+1 và thỏa điều kiện đề bài. Có nghĩa là tồn tại 2 chỉ số k, t sao cho Max{F[u, v]/ u<i, v<j}=F[k,t] và A[k]*2<=A[i]; B[t]*2<=B[j]

Nhận xét:

  • Nếu cài đặt thông thường (sử dụng 4 vòng for i, j, u, v) độ phức tạp O(N4) chỉ giải quyết được 30% test.
  • Nếu ta thấy dãy con chung ( các phần tử được chọn ở dãy A và B giống nhau) ta có thể giải quyết với độ phức tạp O(N3) cụ thể:

Tính F[i, j]=  Max{F[i, v]/  v<j}+1 và thỏa điều kiện đề bài. Có nghĩa là tồn tại  chỉ số  t sao cho Max{F[i, v]/ v<j}=F[i,t] và B[t]*2<=A[i];

Với cách giải quyết này ta chỉ giải quyết được 60% test.

  • Để giải quyết hết các test ta có thể tính trước như sau:

+ Với mỗi i ta gọi Max_T là Max{F[i, j] đã được tính}và thỏa điều kiện đề bài.

+ Với mỗi i ta gọi D[j] là Max{F[i, j] đã được tính}

+ Khi đó F[i, j]= Max_T +1    Khi A[i]=B[j]

+ Max_T được cập nhật khi A[i]>=B[j]*2

+ D[j] được cập nhật khi A[i]=B[j]

 

3. Code tham khảo LCS2X spoj (pascal, C++)

 

[sociallocker]

a. Code LCS2X spoj Pascal

uses    math;
const   fi='';
        nmax=1500+100;
type
        data=longint;
var
        f:text;
        n,m,test:data;
        a,b,d:array[0..nmax] of data;
        C:array[0..nmax,0..nmax] of data;
        gtmax,res:data;

procedure QHD;
var     i,j:data;
begin
        res:=0;
        for i:=0 to n do
                d[i]:=0;

        for i:=1 to m do
                begin
                        gtmax:=0;
                        for j:=1 to n do
                                begin
                                        if a[i]=b[j] then
                                                c[i,j]:=gtmax+1;
                                        if a[i]>=2*b[j] then
                                                gtmax:=max(gtmax,d[j]);
                                        if a[i]=b[j] then
                                                begin
                                                        res:=max(res,c[i,j]);
                                                        d[j]:=max(d[j],c[i,j]);
                                                end;
                                end;
                end;
        writeln(res);
end;

procedure docfile;
var     i,j:data;
begin
        assign(f,fi); reset(f);
        readln(f,test);
        for i:=1 to test do
                begin
                        read(f,m,n);
                        for j:=1 to m do
                                read(f,a[j]);
                        for j:=1 to n do
                                read(f,b[j]);
                        QHD;
                end;

        close(f);
end;


begin
        docfile;
end.

b. Code LCS2X spoj C++

include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int main()
{
    //freopen("test.inp","r",stdin);
    int t,m,n,i,j,a[1505],b[1505],c[1505],cur,prev;
    scanf("%d",&t);
    while(t--)
    {
        memset(c,0,sizeof(c));
        scanf("%d%d",&m,&n);
        for(i=0;i<m;++i) scanf("%d",&a[i]);
        for(i=0;i<n;++i)
        scanf("%d",&b[i]);
        for(i=0;i<m;++i)
        {
            cur=0;
            for(j=0;j<n;++j)
            {
                prev=cur;
                if(2*b[j]<=a[i]) cur=max(cur,c[j]);
                if(a[i]==b[j]) c[j]=max(c[j],prev+1);
            }
        }
        cur=0;
        for(i=0;i<n;++i) cur=max(cur,c[i]);
        printf("%dn",cur);
    }
}

 

[/sociallocker]

 

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *