Thứ Sáu, 11 tháng 1, 2019

Ngày 12-1-2019 - Bài 3

GCDFIB - Ước chung lớn nhất của dãy fibonacci
Dữ liệu vào: standard input
Dữ liệu ra: standard output
Giới hạn thời gian: 1.0 giây
Giới hạn bộ nhớ: 256 megabyte
Đăng bởi: namnguyen123

Dãy số fibonacci được quy ước như sau : 
           F1 = 1 , F= 1 , Fn  = Fn - 1  + Fn - 2 ( n > 3) . 
 
Cho tập A =  { F, FL + 1  , ... , F } (Với F là số fibonacci thứ i ) .
 
Yêu cầu : Hãy xác đinh giá trị lớn nhất của UCLN của các phần tử tập S là tập con của A có đúng K phần tử.
 
Kết quả : Lấy phần dư khi chia kết quả cho MOD . 
 
Input : 
  • Gồm 1 dòng chứa các số nguyên dương MOD , L , R , K
  • ( 1  <  MOD  < 109  ;  1  <  L  <  R  < 1012  ;  1 <  K  <  R - L + 1 ).
Output :
  • Kết quả lấy dư khi chia cho MOD.
 
  
  

Ví dụ

  • input
    10 1 8 2
    output
    3
  • input
    10 1 8 3
    output
    1
8 số đầu là 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21
Nếu k = 2 thì kết quả là 3 vì UCLN của tập {3 , 21} là 3 là số lớn nhất .
Nếu k = 3 thì kết quả là 1 vì UCLN các tập có độ dài 3 đều có UCLN là 1 .
Lời giải:
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
#define long long long

long mod, l, r, k;
map<long, long> f;

bool check(long i) {
    return (r / i - (l - 1) / i >= k);
}

long getF(long n) {
    if (f.count(n)) return f[n];
    long k = n / 2;
    if (n % 2 == 0) return (f[n] = (getF(k) * getF(k) + getF(k - 1) * getF(k - 1)) % mod);
    return (f[n] = (getF(k) * getF(k + 1) + getF(k - 1) * getF(k)) % mod);
}

int main() {
    cin >> mod >> l >> r >> k;
    long id = 0;
    for (long i = 1; i * i <= r; ++i) {
        if (check(i)) id = max(id, i);
        if (check(r / i)) id = max(id, r / i);
    }
    f[0] = f[1] = 1;
    cout << getF(id - 1);
    return 0;
}

Ngày 12-1-2019 - Bài 2

P2GRP - Tổng các đường đi ngắn nhất
Dữ liệu vào: standard input
Dữ liệu ra: standard output
Giới hạn thời gian: 1.0 giây
Giới hạn bộ nhớ: 512 megabyte
Đăng bởi: namnguyen123

Quốc Vương Có Học muốn Mảnh Đất Trí Tuệ trở nên trí tuệ hơn. Vậy làm thế nào để trí tuệ? Trước tiên, trí tuệ
bắt đầu từ những thứ thân thuộc xung quanh chúng ta. Do vậy, chỉ cần thay đổi chúng, ta có thể trở nên trí tuệ
hơn (?). Có Học đã tìm ra một thứ thân thuộc với tất cả người dân mà chưa đạt tới trí tuệ tuyệt đối. Bạn có đoán
ra là gì không? Đó chính là đường đi, hay chính xác hơn là đường đi giữa các thành phố.
Tại Mảnh Đất Trí Tuệ, các thành phố đều được kết nối với nhau bằng những con đường hai chiều giữa chúng
(không có con đường nào nối một thành phố với chính nó và không có hai con đường cùng nối một cặp thành
phố). Quốc Vương Có Học quyết định hạ lệnh cho kĩ sư Đỉnh Cao phải thiết kế độ dài của các con đường một
cách trí tuệ, như thế mới làm đất nước trí tuệ lên được.
Sau nhiều ngày vắt óc, Đỉnh Cao nghĩ ra một thiết kế thật sự đỉnh cao: độ dài các con đường là một lũy thừa của
hai và đôi một khác nhau. Để kiểm chứng sự hiệu quả, Đỉnh Cao cần tính tổng các đường đi ngắn nhất giữa mọi
cặp thành phố và càng sớm càng tốt để yết kiến Quốc Vương.
Đỉnh Cao quyết định nhờ bạn tính hộ để anh còn kiểm tra lại sự đỉnh cao và trí tuệ của bản thiết kế. Liệu bạn có
thể tính thay Đỉnh Cao?
INPUT
Dòng đầu gồm hai số n, m tương ứng với số thành phố và số đường đi. 

m dòng sau, mỗi dòng ghi 3 số u , v , w  cho biết giữa 2 đỉnh u , v có cạnh trọng số 2^w
OUTPUT
In ra đáp án dưới dạng nhị phận . 

GIỚI HẠN
Tất cả các test có n ≤ 105 , m  ≤  2 * 105 ,  w < m . 

Nguồn bài : HSGSO 2017

 

Ví dụ

  • input
    3 3
    1 2 0
    1 3 1
    2 3 2
    output
    110

Đường đi ngắn nhất (1 -> 3 ) : 2 , (2 -> 3) : 3 ; (1 -> 2) : 1 Tổng là 6 (110)

 

Lời giải:
using namespace std;
#include<bits/stdc++.h>
#define st first
#define nd second
#define FORE(i,a,b) for(int i=(a),b_=(b);i<=b_;++i)
#define FORD(i,a,b) for(int i=(a),b_=(b);i>=b_;--i)
#define TR(c, it) for(__typeof((c).begin()) it=(c).begin(); it!=(c).end(); it++)

const int MOD = 1e9 + 7 ;
const int MAXN = 1e5 + 5 ;
int par[MAXN], n , m ;
vector < pair < int, pair < int, int > > > Edeges, New ;
int findSet (int p)
{
    if (par[p] == p) return par[p] ;
    else return par[p] = findSet(par[p]) ;
}
void join (int u, int v)
{
    int x = findSet(u), y = findSet(v) ;
    par[y] = x ;
}
long long nChild[MAXN] ;
vector <int> g[MAXN] ;
void DFS (int u , int par )
{
    nChild[u] = 1 ;
    TR(g[u] , it)
    {
        int v = *it ;
        if (v == par) continue ;
        DFS(v , u) ;
        nChild[u] += nChild[v] ;
    }
}
long long ans[5 * MAXN] ;
int main()
{
#define TASK "NAME"
    // freopen(TASK".inp","r",stdin);
    // freopen(TASK".out","w",stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m ;
    for(int i = 1 ; i <= n ; ++i ) par[i] = i ;
    for(int i = 1 ; i <= m ; ++i )
    {
        int u, v, w ;
        cin >> u >> v >> w ;
        Edeges.push_back(make_pair(w , make_pair(u , v)) ) ;
    }
    sort(Edeges.begin(), Edeges.end() ) ;
    TR(Edeges , it)
    {
        int w = it -> st ;
        int u = (it -> nd).st ;
        int v = (it -> nd).nd ;
        if (findSet(u) == findSet(v) ) continue ;
        New.push_back(make_pair(w , make_pair(u , v))) ;
        join(u , v) ;
        g[u].push_back(v) ;
        g[v].push_back(u) ;
    }
    DFS(1 , -1) ;
    TR(New , it) {
        int w = it -> st ;
        int u = (it -> nd).st ;
        int v = (it -> nd).nd ;
        ans[w] += 1LL * (n - min(nChild[u] , nChild[v])) * min(nChild[u] , nChild[v]) ;
    }
    int sz = m - 1 ;
    for(int i = 0 ; i < m - 1 ; ++i ) ans[i + 1] += (ans[i] >> 1) , ans[i] = ans[i] & 1 ;
    while(1){
        if (ans[sz] > 1) {
            ans[sz + 1] += (ans[sz] >> 1 ) ;
            ans[sz] = ans[sz] & 1 ;
            sz ++ ;
        }
        else
            break ;
    }
    while(ans[sz] == 0)
        sz--;
    for(int i = sz ; i >= 0 ; --i )
    cout << ans[i] ;
    return 0;
}

Ngày 12-1-2019 - Bài 1

AMPHO - Âm phổ
Dữ liệu vào: standard input
Dữ liệu ra: standard output
Giới hạn thời gian: 1.0 giây
Giới hạn bộ nhớ: 128 megabyte
Đăng bởi: admin

Nam rất thích nghe nhạc và trong lúc nghe nhạc thì việc cậu thích tiếp theo là quan sát sự thay đổi âm phổ như trong hình bên dưới
Âm phổ gồm n cột có chiều cao lần lượt là a1, a2, ..., an. Chiều cao tối đa của một cột là m. Bạn hãy giúp Nam vẽ lại hình âm phổ nhé.
Dữ liệu nhập:
- Dòng đầu tiên là hai số nguyên n và m cách nhau một khoảng trắng (1 ≤ n ≤ 20, 1 ≤ m ≤ 20)
- Dòng tiếp theo gồm n số nguyên a1, a2, ..., an, mỗi số cách nhau một khoảng trắng (0 ≤ ai ≤ m).
Dữ liệu xuất:
- Gồm m dòng tạo thành bảng thể hiện âm phổ, mỗi dòng gồm n ký tự # hoặc dấu chấm. Các cột âm phổ được biểu diễn bằng dấu #, phần còn lại biểu diễn bằng dấu chấm (xem ví dụ để hiểu rõ thêm)

Ví dụ

  • input
    5 5
    4 2 4 1 2
    output
    .....
    #.#..
    #.#..
    ###.#
    #####
  • input
    8 5
    4 3 2 1 1 2 3 4
    output
    ........
    #......#
    ##....##
    ###..###
    ########
Lời giải:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000001];
int main ()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)    cin >> a[i];
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (a[j] + i > m)   cout << "#";
            else    cout << ".";
        }
        cout << '\n';
    }
}

Ngày 11-1-2019 - Bài 3

SMINROAD - Đường đi trọng số nhỏ nhất
Dữ liệu vào: standard input
Dữ liệu ra: standard output
Giới hạn thời gian: 2.0 giây
Giới hạn bộ nhớ: 256 megabyte
Đăng bởi: namnguyen123

Cho đồ thị vô hướng n đỉnh , m cạnh . Trên mỗi đỉnh của đồ thị , có gắn một số tượng trưng cho giá trị của đỉnh đó . Trọng số của một đường đi chính bằng giá trị nhỏ nhất của các đỉnh thuộc đường đi đó . F(u , v) là giá trị lớn nhất trong của trọng số của các đường đi từ u -> v .
Yêu cầu : Tính tổng các F(u , v) với (u # v) .

INPUT :
Dòng đầu tiên gồm 2 số nguyên dương n , m ( n < 105  , m < 2.105 ) . 
Dòng thứ 2 gồm n số là giá trị các đỉnh : a1 , a2 , .. , an . ( 0 < ai < 109 ). 
m dòng tiếp theo là các cạnh đồ thị . Mỗi dòng gồm 2 số nguyên dương u , v ( 1 < u , v < n ). 
OUTPUT : 
Kết quả bài toán . 

Ví dụ

  • input
    4 3
    10 20 30 40
    1 3
    2 3
    4 3
    output
    200
  • u = 1 ,  v = 3 ,  F(u , v)  = 10.
  • u = 2 ,  v = 3 ,  F(u , v)  = 20.
  • u = 4 ,  v = 3 ,   F(u , v)  = 30.
  • u = 1 ,  v = 2 ,   F(u , v)  = 10.
  • u = 2 ,  v = 4 ,   F(u , v)  = 20.
  • u = 4 ,  v = 1 ,   F(u , v)  = 10.
​Tổng là 100 x 2 = 200 . 
Lời giải:
#include <bits/stdc++.h>
using namespace std;
long long kq,k;
int sl[100001],r[100001],n,m,i,u,v,c[100001],r1,r2,d;
struct pt
{
    int u,v,k;
};
pt a[200001];
bool cmp(pt a,pt b)
{
    return a.k>b.k;
}
int root(int u)
{
    if(u==r[u]) return u;
    r[u]=root(r[u]);
    return r[u];
}
void hop(int u,int v)
{
    int s1=sl[u],s2=sl[v];
    kq+=s1*s2*k;
    if(s1>s2)
    {
        r[v]=u;
        sl[u]=s1+s2;
    }
    else
    {
        r[u]=v;
        sl[v]=s1+s2;
    }
}
int main()
{
    //freopen("ntu.inp","r",stdin);
    //freopen("ntu.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        r[i]=i; sl[i]=1;
    }
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        a[i]={ u,v,min(c[u],c[v]) };
    }
    sort(a+1,a+m+1,cmp);
    for(i=1;i<=m;i++)
    {
        u=a[i].u; v=a[i].v; k=a[i].k;
        r1=root(u); r2=root(v);
        if(r1==r2) continue;
        hop(r1,r2); d++;
        if(d==n-1) break;
    }
    printf("%lld",2*kq);
}

Bài G - Educatioal Round 62

Đề bài: Bạn được cho 1 đồ thị vô hướng đặc biệt. Nó bao gồm $2n$ đỉnh được đánh số từ 1 đến 2n. Dưới đây là một số đặc tính của đồ thị: + ...