STABLE – spoj

Đề bài:

Thuật toán:

  • BFS từ đỉnh S
  • Gọi bac[i] là đồ dài đường đi ngắn nhất từ s đến i
    • bac[i] = bac[j] + 1
    • với i kề j và j duyệt BFS trước i
  • ok[i] = 1 nếu i ổn định, ok[i] = 0 nếu i không ổn định.
  • Hãy tham khảo code để biết cách kiểm tra xem i có ổn định không

Code:

#include 
using namespace std;
#define FOR(i,a,b) for (int i=(a),_b=(b);i<=_b;i=i+1)
#define FORD(i,b,a) for (int i=(b),_a=(a);i>=_a;i=i-1)
#define REP(i,n) for (int i=0,_n=(n);i<_n;i=i+1)
#define FORE(i,v) for (__typeof((v).begin()) i=(v).begin();i!=(v).end();i++)
#define ALL(v) (v).begin(),(v).end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define double db
typedef long long ll;
typedef pair PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const int MAXN = 1E4+3;
const int oo = 1e9+3;

int n, m, s, u, v, res, bac[MAXN],adj[MAXN][MAXN];
bool ok[MAXN];
queue q;
vector a[MAXN];

int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("test.inp", "r", stdin);
    	freopen("test.out", "w", stdout);
    	#endif
    cin >> n >> m >> s;
    FOR(i,1,m) {
        cin >> u >> v;
        if (!adj[u][v])
            a[u].push_back(v);
        adj[u][v] = 1;
    }
    q.push(s); bac[s] = 1;
    while (!q.empty()) {
        u = q.front();
        q.pop();
        for(int i=0; i
const
  fi='stable.inp';
  fo='stable.out';
  maxn=10000;
  maxm=50000;
var
  link,head,ke : array[1..maxm] of longint;
  i,j,n,m,st,ans,s,dau,cuoi,u,v : longint;
  q,bac : array[1..maxn] of longint;
  ok : array[1..maxn] of boolean;
  a : array[1..maxn,1..maxn] of boolean;
procedure push(x : longint);
  begin
    inc(cuoi);
    q[cuoi] := x;
  end;
procedure add(i,u,v : longint);
  begin
    link[i] := head[u];
    head[u] := i;
    ke[i] := v;
  end;
begin
//  assign(input,fi);reset(input);
//  assign(output,fo);rewrite(output);
  read(n,m,s);
  for i := 1 to m do
    begin
      read(u,v);
      if a[u,v] = false then
      add(i,u,v);
      a[u,v] := true;
    end;
  dau := 1; cuoi := 0;
  push(s);
  bac[s] := 1;
  while (dau <= cuoi) do
    begin
      u := q[dau];
      inc(dau);
      i := head[u];
      while i <> 0 do
        begin
          v := ke[i];
          if bac[v] = 0 then
            begin
              if ok[u] then ok[v] := true;
              bac[v] := bac[u] + 1;
              push(v);
            end
            else
          if bac[v] = bac[u] + 1 then
            begin
              ok[v] := true;
            end;
          i := link[i];
        end;
    end;
  for i := 1 to n do
    if ok[i] then inc(ans);
  writeln(ans);
//  close(input);close(output);
end.

listgame – kattis

[mathjax]
[su_accordion][su_accordion]
[su_spoiler title=”Đề bài” open=”yes”]
Có hai người chơi trò chơi với nhau, luật như sau:

  • Người thứ nhất chọn một số nguyên dương X
  • Người thứ hai tìm các số $Y_1, Y_2, .. Y_k$ sao cho $(Y_1 + 1)(Y_2 + 1)…(Y_k + 1) = X$. Khi đó người chới thứ hai được k điểm

Cho X tìm số điểm tối đa mà người chơi thứ hai có thể đạt

Input:

Số nguyên dương $X$ thỏa mãn $10^3 <= X <= 10^9$

Output:

Duy nhất số K là số điểm tối đa có thể đạt

Sample Input 1 65536
Sample Output 1 16

 

Sample Input 2 127381
Sample Output 2 3

[/su_spoiler]
[su_spoiler title=”Thuật toán”]

  • Nếu n là số nguyên tố => Kết quả: 1
  • Nếu không thì ta phần tích X thành tích các số nguyên tố => Kết quả: là số các số hạng phân tích được
  • Ví dụ: 12 = 2 * 2 * 3 => Kết quả: 3

[/su_spoiler]
[su_spoiler title=”Code”]

#include 
using namespace std;
#define FOR(i,a,b) for (int i=(a),_b=(b);i<=_b;i=i+1)
#define FORD(i,b,a) for (int i=(b),_a=(a);i>=_a;i=i-1)
#define REP(i,n) for (int i=0,_n=(n);i<_n;i=i+1)
#define FORE(i,v) for (__typeof((v).begin()) i=(v).begin();i!=(v).end();i++)
#define ALL(v) (v).begin(),(v).end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define double db
typedef long long ll;
typedef pair PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const int MAXN = 1E6+3;
const int oo = 1e6+3;

bool prime[MAXN];
int i, j, x, cnt, k, sl[MAXN], nt[MAXN];

void tim_snt() {
    prime[1] = 1;
    int n = trunc(sqrt(oo));
    for(i=2; i<=n; i++) {
        if (!prime[i]) {
            j = i*i;
            while (j <= oo) {
                prime[j] = 1;
                j += i;
            }
        }
    }
    cnt = 0;
    for(i=2; i<=oo; i++) if (!prime[i]) {
        cnt++;
        nt[cnt] = i;
    }
}

void phan_tich() {
    int i = 1;
    while (x > 1) {
        while ((x > 1)&&(x % nt[i] == 0))
        {
            k++;
            x /= nt[i];
        }
        i++;
        if (i > cnt) break;
    }
    if (x > 1) k++;
}

bool ktnt(int x) {
    int n = trunc(sqrt(x));
    FOR(i,2,n) {
        if (x % i == 0) return 0;
    }
    return 1;
}

int main() {
    cin >> x;
    if (ktnt(x)) {
        cout << 1;
        return 0;
    }
    tim_snt();
    phan_tich();
    cout << k;
    return 0;
}

[/su_spoiler]
[/su_accordion]

UPGRANET – spoj

Đề bài:


Thuật toán:


Ta thấy thông lượng truyền tin từ u đến v là giá trị lớn nhất của cạnh nhỏ nhất trên mọi con đường từ u đến v.
Vì vậy, ban đầu, ta sẽ xây dựng cây khung lớn nhất(tương tự như cây khung nhỏ nhất nhưng sort ngược lại).

Gọi dis(u,v) là cạnh có trọng số nhỏ nhất khi đi từ u đến v trên cây vừa tạo. Ta chọn nút 1 làm gốc, duyệt dfs để lưu trữ cạnh nhỏ nhất và các nút cha của u khi đi từ 1 đến u (đều dùng RMQ). Với mỗi 1 cạnh không nằm trong cây khung, ta tìm nút cha chung gần nhất(gọi là p), kết quả cộng thêm một lượng bằng hiệu của min(dis(u, p), dis(v, p)) và rọng số cạnh đang xét.

Code:


#include 
#define maxn 1000005
#define maxm 10000005
#define maxc 1000000007
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define pii pair
#define fort(i, a, b) for(int i = (a); i <= (b); i++)
#define ford(i, a, b) for(int i = (a); i >= (b); i--)
#define Task "UPGRANET"
#define fast ios_base::sync_with_stdio(0);cin.tie();cout.tie();
#define stop1 {cout << "-1\n"; return;}
#define stop2 {cout << "0\n"; return;}
#define stop3 {cout << "yes\n"; exit(0);}
#define skip1 {cout << "Yes\n"; continue;}
#define skip2 {cout << "No\n"; continue;}
#define ll long long

using namespace std;

ll n, m, root[maxn], h[maxn], res;
pii  par[maxn][20];
bool dd[maxn];
vector > ke[maxn];
struct canh
{
    ll u, v, w;
}ed[maxn];

void setup()
{
    cin >> n >> m;
    fort(i, 1, m)
        cin >> ed[i].u >> ed[i].v >> ed[i].w;
}

bool cmp(canh p, canh q)
{
    return p.w > q.w;
}

ll getroot(ll u)
{
    if(root[u] == 0) return u;
    return root[u] = getroot(root[u]);
}

void make_tree()
{
    sort(ed+1, ed+m+1, cmp);
    fort(i, 1, m)
    {
        ll p = getroot(ed[i].u);
        ll q = getroot(ed[i].v);
        if(p == q) continue;
        root[p] = q;
        dd[i] = 1;
        ke[ed[i].u].pb(mp(ed[i].v, ed[i].w));
        ke[ed[i].v].pb(mp(ed[i].u, ed[i].w));
    }
}

void dfs(ll u, ll tr)
{
    fort(i, 0, int(ke[u].size()) - 1)
    {
        ll v = ke[u][i].F;
        if(v == tr) continue;
        h[v] = h[u] + 1;
        par[v][0] = mp(u,ke[u][i].S);
        fort(j, 1, 18)
        {
            par[v][j].F = par[par[v][j-1].F][j-1].F;
            par[v][j].S = min(par[par[v][j-1].F][j-1].S, par[v][j-1].S);
        }
        dfs(v, u);
    }
}

pii lca(ll u, ll v)
{
    pii p;
    p.S = 1ll* maxc * maxc;
    if( h[u] > h[v])
        swap(u, v);
    ll diff = h[v] - h[u];
    ford(i, 18, 0)
        if((diff >> i) & 1)
        {
            p.S = min(p.S, par[v][i].S);
            v = par[v][i].F;

        }
    if(v == u) return mp(u, p.S);
    ford(i, 18, 0)
        if(par[u][i].F != par[v][i].F)
        {
            p.S = min(p.S, min(par[v][i].S, par[u][i].S));
            v = par[v][i].F;
            u = par[u][i].F;
        }
    return mp(par[u][0].F, min(p.S, min(par[u][0].S, par[v][0].S)));
}

void work()
{
    make_tree();
    h[1] = 1;
    dfs(1, 0);
    fort(i, 1, m)
        if(!dd[i])
        {
            pii l = lca(ed[i].u, ed[i].v);
            res += max(0ll, l.S - ed[i].w);
        }
    cout << res;
}


int main()
{
    fast
  //  freopen(Task".inp", "r", stdin);
  //  freopen(Task".out", "w", stdout);
    setup();
    work();
    return 0;
}

Cowboy

VCOWFLIX – spoj

Đề bài: http://vn.spoj.com/problems/VCOWFLIX/

Thuật toán:

  • Gọi L[i][j] tổng khối lượng bò lớn nhất mà John có thể mang đi xem phim khi có i con bò và sức chứa của xe là j.
    • Nếu a[i]<=j thì L[i,j]:=max(L[i-1,j], L[i-1,j-a[i]]+a[i]);
    • Nếu a[i]>j thì L[i,j]:=L[i-1,j];

Code:

uses    math;
const   fi='';
        fo='';
        maxn=16;
        oo=5000;
var     l:array[0..maxn,0..5000] of longint;
        a:array[1..maxn] of longint;
        i,j,c,n:longint;
begin
        assign(input,fi);reset(input);
        assign(output,fo);rewrite(output);

        readln(c,n);
        for i:=1 to n do read(a[i]);

        for i:=1 to n do
                for j:=0 to c do
                        begin
                            l[i,j]:=l[i-1,j];
                            if a[i]<=j then
                                l[i,j]:=max(l[i,j],l[i-1,j-a[i]]+a[i]);
                        end;

        writeln(l[n,c]);

        close(input);close(output);
end.

Các cấu trúc điều khiển trong C++

Cấu trúc lặp for

   for(biểu_thức_1; biểu_thức_2; biểu_thức_3)
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }
  • Ý nghĩa từng biểu thức:
  • biểu_thức_1: thường dùng khởi tạo biến đếm vòng lặp.
  • biểu_thức_2: thường dùng kiểm tra điều kiện vòng lặp.
  • biểu_thức_3: thường dùng điều khiển biến đếm của vòng lặp
  • Ví dụ: for(int i=0; i<10; i++)
  • Thứ tự thực hiện:
    • Bước 1: Xác định biểu_thức_1
    • Bước 2: Xác định biểu_thức_2
    • Bước 3: Nếu biểu_thức_2 đúng chương trình sẽ thực hiện khối lệnh trong vòng lặp for. Ngược lại thoát khỏi for.
    • Bước 4: Tính biểu_thức_3, sau đó quay lại bước 2 để bắt đầu vòng lặp mới.

Cấu trúc điều khiển rẽ nhánh if

   if(biểu_thức_điều_kiện)
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }

Cấu trúc điều khiển rẽ nhánh if…else

   if(biểu_thức_điều_kiện)
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }
   else
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }

Cấu trúc điều khiển switch

   switch(biều_thức_chọn)
   {
      case Giá_trị_1:
            Lệnh_1;
            Lệnh_2;
            ...
            break;
      case Giá_trị_2:
            Lệnh_1;
            Lệnh_2;
            ...
            break;
      default:
            Lệnh_1;
            Lệnh_2;
            ...
            break;
   }
  • biều_thức_chọn trong switch sẽ được so sánh với các giá trị trong tương ứng với các mệnh đề case.
  • Nếu giá trị biều_thức_chọn bằng Giá_trị_i thì khối lệnh của case i được thực hiện. Ngược lại thì khối lệnh tương ứng với khóa default được thực hiện.

Cấu trúc điều khiển lặp while

   while(<điều_kiện_lặp)
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }
  • Điều kiện lặp được kiểm tra trước khi thực hiện khối lệnh

Cấu trúc lặp while

   do
   {
      Câu lệnh 1;
      ...
      Câu lệnh n;
   }while(điều_kiện_lặp);
  • Điều kiện lặp được kiểm tra khi khối lệnh được thực hiện xong. Do đó khối lệnh trong vòng lặp được thực hiện ít nhất 1 lần

SHHV – spoj

Đề bài:

Thuật toán:

  • (đang cập nhập)

Code:

#include 
using namespace std;
#define FOR(i,a,b) for (int i=(a),_b=(b);i<=_b;i=i+1)
#define FORD(i,b,a) for (int i=(b),_a=(a);i>=_a;i=i-1)
#define REP(i,n) for (int i=0,_n=(n);i<_n;i=i+1)
#define FORE(i,v) for (__typeof((v).begin()) i=(v).begin();i!=(v).end();i++)
#define ALL(v) (v).begin(),(v).end()
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define double db
typedef long long ll;
typedef pair PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
const int MAXN = 13;
const int oo = 1e9+3;
string s;

ll gt[MAXN+1];
int n, x, a[MAXN+1], b[MAXN+1], i, j;
bool chon[MAXN+1];
ll t;

void init() {
    gt[0] = 1;
    gt[1] = 1;
    for (int i=2; i<=MAXN; i++) gt[i] = gt[i-1]*i;
}

void query1() {
    ll ans = 0;
    memset(chon,0,sizeof(chon));
    for (int i=1; i<=n; i++) {
        for (int j=1; j<=a[i]-1; j++)
        if (!chon[j]) {
            ans += gt[n-i];
        }
        chon[a[i]] = 1;
    }
    cout << ans+1 << endl;
}

void query2() {
    memset(chon,0,sizeof(chon));
    t--;
    for (i=1; i<=n; i++) {
        int tmp = 0;
        for (j=1; j<=n; j++) {
            if (!chon[j]) tmp++;
            if (gt[n-i]*tmp>t) break;
        }
        t -= gt[n-i]*(tmp-1);
        b[i] = j;
        chon[j]=1;
    }
    for (int i=1; i<=n; i++) cout << b[i] << " ";
}

int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("test.inp", "r", stdin);
    	freopen("test.out", "w", stdout);
    	#endif
    while (cin>>a[++n]);
    t=a[--n]; n--;
    init();
    query1();
    query2();
    return 0;
}

BONUS13 – spoj

Đề bài:

Thuật toán:

Code:

uses    math;
const   fi='';
        fo='';
        maxn=80;
        n=8;
        hx:array[1..8] of integer=(-1,-2,-2,-1,1,2,2,1);
        hy:array[1..8] of integer=(-2,-1,1,2,2,1,-1,-2);
type    point=record
                x,y:byte;
                end;
var     cx,dx:array[1..maxn] of point;
        a:array[1..8,1..8] of boolean;
        c:array[1..maxn] of longint;
        i,j,k:longint;
        top1,top2:longint;
        hau,xe,ma,tuong:array[1..maxn,1..maxn] of boolean;
        m,t,x,h : longint;
        res:int64;
procedure nhap;
var     u,v:byte;
        w:longint;
begin
    assign(input,fi);reset(input);
    readln(k);
    for i:=1 to k do
        begin
            readln(u,v,w);
            a[u,v]:=true;
            inc(top1); dx[top1].x:=u; dx[top1].y:=v; c[top1]:=w;
        end;
    close(input);
end;
procedure init;
begin
    res:=0;
    for i:=1 to 8 do
        for j:=1 to 8 do
                if a[i,j]=false then
                        begin
                               inc(top2);
                               cx[top2].x:=i;
                               cx[top2].y:=j;
                        end;
end;
function chau(i,j:longint):boolean;
begin
    if cx[i].x=dx[j].x then exit(true);
    if cx[i].y=dx[j].y then exit(true);
    if (cx[i].x+cx[i].y)=(dx[j].x+dx[j].y) then exit(true);
    if (cx[i].x-cx[i].y)=(dx[j].x-dx[j].y) then exit(true);
    exit(false);
end;
function cxe(i,j:longint):boolean;
begin
    if cx[i].x=dx[j].x then exit(true);
    if cx[i].y=dx[j].y then exit(true);
    exit(false);
end;
function ctuong(i,j:longint):boolean;
begin
    if (cx[i].x+cx[i].y)=(dx[j].x+dx[j].y) then exit(true);
    if (cx[i].x-cx[i].y)=(dx[j].x-dx[j].y) then exit(true);
    exit(false);
end;
function cma(i,j:longint):boolean;
var     k,u,v:integer;
begin
    for k:=1 to 8 do
        begin
            u:=cx[i].x+hx[k];
            v:=cx[i].y+hy[k];
            if (u=dx[j].x) and (v=dx[j].y) then exit(true);
        end;
    exit(false);
end;
procedure xuly;
var     i,j:longint;
begin
    for i:=1 to top2 do
        for j:=1 to top1 do
         begin
          if chau(i,j) then hau[i,j]:=true;
          if cxe(i,j) then xe[i,j]:=true;
          if cma(i,j) then ma[i,j]:=true;
          if ctuong(i,j) then tuong[i,j]:=true;
         end;
end;
procedure main;
var     tam:int64;
begin
    for h:=1 to top2 do
        for x:=1 to top2 do
                if h<>x then
                        for m:=1 to top2 do
                                if (m<>h) and (m<>x) then
                                        for t:=1 to top2 do
                                                if (m<>t) and (t<>x) and (t<>h) then
                                                  begin
                                                        tam:=0;
                                                        for i:=1 to top1 do
                                                                if hau[h,i] or xe[x,i] or ma[m,i] or tuong[t,i] then tam := tam + c[i];
                                                        res:=max(res,tam);
                                                  end;

end;
procedure inkq;
begin
    assign(output,fo);rewrite(output);
    writeln(res);
    close(output);
end;
begin
    nhap;
    init;
    xuly;
    main;
    inkq;
end.
#include 
#include 
using namespace std;
#define LL long long
#define rep(i, a, b) for (int i=a; i& a) {
    LL res = 0;
    for (auto &x: a) {
        if (state & 1) res += x.w;
        state >>= 1;
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int m; cin >> m;
    vector a(m);
    vector frei(64, true);
    for (auto &a: a) {
        cin >> a.x >> a.y >> a.w;
        a.x--, a.y--;
        frei[a.x*8+a.y] = false;
    }
    vector xe(64, 0), tuong(64, 0), ma(64, 0), hau(64, 0);
    int c = 0;
    rep(i, 0, 8) rep(j, 0, 8) if (frei[c]) {
        rep(k, 0, m) {
            int x = a[k].x, y = a[k].y;
            if (x==i || y==j) xe[c] |= 1ll<

C11CAVE – spoj

Đề bài:

Thuật toán:

  • Chỉ cần duyệt từ 1 đến h rồi kiểm tra, bạn đọc code bên dưới sẽ hiểu.

Code:

    const           fi      = '';
                    fo      = '';
                    maxn    = 1000000;

    var
                    n , h   : longint;
                    m       : longint;
                    d , c   : array[ 0..maxn ] of longint;

    procedure   enter;
        var
                i           : longint;
                u , v       : longint;
        begin
                read( n , h );
                m := n div 2;
                for i := 1 to m do
                  begin
                    read( u , v );
                    inc( d[ u ] );
                    inc( c[ v ] );
                  end;
        end;

    procedure   prepair;
        var
                i           : longint;
        begin
                for i := 1 to h do
                  begin
                    d[ i ] := d[ i-1 ] + d[ i ];
                    c[ i ] := c[ i-1 ] + c[ i ];
                  end;
        end;


    procedure   solve;
        var
                res , num   : longint;
                i , tmp     : longint;
        begin
                res := n+1;
                num := 0;
                for i := 1 to h do
                  begin
                    tmp := d[ h ] - d[ i-1 ] + c[ h ] - c[ h-i ];
                    if res > tmp then
                      begin
                        res := tmp;
                        num := 1;
                      end
                    else
                      if res = tmp then inc( num );
                  end;
                writeln( res , ' ' , num );
        end;



    BEGIN

                assign( input , fi ); reset( input );
                assign( output , fo ); rewrite( output );

                enter;
                prepair;
                solve;

                close( input ); close( output );

    END.

MESSAGE1 – spoj

[mathjax]

Đề bài

Thuật toán
message1-yeulaptrinh.pw

Ở bài này ta dời bảng B như hình, trong mỗi lần dời ta so sách các ô trong vùng giao nhau nữa 2 bảng, ô bằng nhau có giá trị 1, khác nhau có giá trị 0.

Cụ thể hơn, giả sử ta dời bảng B theo một vector $(x, y)$, khi đó ô $A(i, j)$ sẽ được so sánh với ô $B(i-x, j-y)$. Ta tính toạ độ các ô trong phần giao giữa 2 bảng như sau, có 4 điều kiện:

$
\begin{cases}
0 <= i < m\\
0 <= j < n\\
0 <= i-x < m\\
0 <= i-y < n\\
\end{cases}
$

Từ đó suy ra:

$
\begin{cases}
max(0, x) <= i < min(m, m + x)\\
max(0, y) <= j < min(n, n + y)\\
\end{cases}
$

Sau đó ta tìm hình chữ nhật chứa toàn số 1 và có diện tích lớn nhất (như bài QBRECT).

Sau đây là cách tìm hình chữ nhật như trên trong thời gian $O(n^2)$:

Với mỗi ô $j$ trên hàng $i$, ta tìm $f(j)$ là số ô 1 liên tiếp trên cột $j$, tính từ hàng $i$ trở lên. Sau đó, với mỗi cột $j$, ta tiếp tục tìm ô gần nhất bên trái và ô gần nhất bên phải có $f$ nhỏ hơn $f(j)$, sau đó tính diện tích hình chữ nhật ở cột $j$ là $S = f(j)\times(r – l – 1)$ với $l, r$ là chỉ số 2 ô bên trái và bên phải nói trên.

Hình minh hoạ khi tính $f(4)$:

message1-2-yeulaptrinh.pw

Để tìm $l, r$ nhanh, ta dùng kĩ thuật sử dụng Deque tìm Min/Max trên đoạn tịnh tiến.

Độ phức tạp của toàn bộ lời giải là $O(n^4)$.

Code

#include 
#include 
#include 
using namespace std;

void calc(int &res, int x, int y, const vector &a, const vector &b) {
    int m = a.size(), n = a[0].size();
    int low_i = max(0, x), high_i = min(m, m + x);
    int low_j = max(0, y), high_j = min(n, n + y);
    if ((high_i - low_i)*(high_j - low_j) <= res) return;
    vector f(high_j, 0);
    vector l(high_j), q(high_j), idx(high_j);
    for (int i=low_i; i < high_i; i++) {
        int top = 0;
        for (int j=low_j; j < high_j; j++) {
            if (a[i][j] == b[i-x][j-y]) {
                f[j]++;
                while (top && q[top-1]>=f[j]) top--;
                if (!top) l[j] = low_j-1;
                else l[j] = idx[top-1];
                q[top] = f[j], idx[top] = j, top++;
            } else {
                f[j] = 0;
                q[0] = 0, idx[0] = j, top = 1;
            }
        }
        top = 0;
        int r;
        for (int j=high_j-1; j >= low_j; j--) {
            if (f[j]) {
                while (top && q[top-1]>=f[j]) top--;
                if (!top) r = high_j;
                else r = idx[top-1];
                res = max(res, f[j]*(r - l[j] - 1));
                q[top] = f[j], idx[top] = j, top++;
            } else {
                q[0] = 0, idx[0] = j, top = 1;
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int T; cin >> T;
    while (T--) {
        int n, m; cin >> m >> n;
        vector a(m), b(m);
        for (auto &s: a) cin >> s;
        for (auto &s: b) cin >> s;
        int res = 0;
        for (int i=-m+1; i

FIBVAL – spoj

Đề bài

Thuật toán

Để giải được bài này, ta cần áp dụng 1 tính chất đặc biệt của dãy Fibonacci, đó là chu kỳ Pisano

Dãy Fibonacci có dạng:

  • f(0) = 0
  • f(1)=1
  • f(i)=f(i-1)+f(i-2)

Đối với 1 số nguyên n bất kì thì dãy g(i)=f(i) mod n có tính chu kì.

Ví dụ: Với n=3 ta có:

f 0 1 1 2 3 5 8 13 15 28 43
g 0 1 1 2 0 2 2 1 0 1 1

Ở bài này, ta có chu kì gồm 7 nốt nhạc vì vậy ta xét tính chu kì trên dãy g(i)=f(i) mod 7.

Chu kì Peisano của 7 trong bài này gồm 16 số:

 1 2 3 5 1 6 0 6 6 5 4 2 6 1 0 1

Như vậy, độ dài đoạn nhạc dài nhất có tính chu kì chỉ có thể là 2 hoặc có dạng 16*k.

Code

CONST
    tfi = '';
    tfo = '';
VAR
    fi,fo           : text;

Function pro(l,r: longint): longint;
    Var
        len,res: longint;
    Begin
        len:=r-l+1;
        l:=l mod 16;
        r:=r mod 16;
        If l=0 then l:=16;
        If r=0 then r:=16;
        res:=len div 16;
        If len>=32 then exit(res*16)
        else
            If len>=9 then exit(2)
            else
                If ((l=9)) or ((l>9) and (r0 do
            begin
                read(fi,l,r);
                writeln(fo,pro(l,r));
                dec(test);
            end;
    End;

BEGIN
    assign(fi,tfi); reset(fi);
    assign(fo,tfo); rewrite(fo);
        process;
    close(fi); close(fo);
END.

Nguồn: không rõ