Codeforces Round #615 (Div. 3)


A. Collecting Coins

題目鏈接:https://codeforces.com/contest/1294/problem/A

題意:

你有三個姐妹她們分別有 a , b , c枚硬幣,你有n枚,你可以把硬幣隨意分給她們(必須分完),使她們的硬幣數A = B = C 

分析:

題目的條件有兩點:

①A = B = C

②在滿足①的前提下必須把硬幣分完

我們首先要滿足第一點。因為硬幣個數有限,我們要盡可能用最少的硬幣使 A = B = C,所以只要讓a,b,c中小的兩個等於最大的即可

那么我們剩下的硬幣數就為 $n-\left( \max -a\right) -\left( \max -b\right) -\left( \max -c\right)$ 判斷剩余數是否大於0即可(是否足夠分配)

對於第二個條件,只要判斷我們剩下的硬幣是否是三的倍數即可(只有為三倍數才可以等量均分保持A = B = C)

#include<bits/stdc++.h>
using namespace std; 
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int a , b , c , n;
        cin >> a >> b >> c >> n;
        int MAX = max(a , max(b , c));
        n -= (MAX - a) + (MAX - b) + (MAX - c);
        if(n < 0 || n % 3 != 0)
        cout << "NO" << '\n';
        else 
        cout << "YES" << '\n';
    }
    return 0;
}
 
 
 
 
   
View Code

 

 

 

B. Collecting Packages

題目鏈接:https://codeforces.com/contest/1294/problem/B

題意:

有n個盒子需要你撿,第i個盒子的坐標為 (Xi , Yi)。你從(0,0)出發,每次只能選擇向上或者向右移動,問能否將n個盒子都撿完,若可以撿完,則輸出字典序最小的一條路線

分析:

我們將n個盒子的坐標先按照x值再按照y值排序。因為是按照 X 升序排序的,所以當 Yi  > Yi + 1 時,很顯然此時第i個盒子和第i+1個盒子有一個不能走到

而 Yi <= Yi+1 時,為了保證字典序最小,我們先加上(Xi+1 - Xi)個L, 再加上(Yi+1 - Yi)個縱坐標即可

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
const int N = 2e5 + 10;
pair<int , int> ha[N];
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n , flag = 1 ; string ans = "";
        cin >> n;
        for(int i = 1 ; i <= n ; i ++)
            cin >> ha[i].fi >> ha[i].se;
        ha[0].fi = 0 , ha[0].se = 0;
        sort(ha , ha + 1 + n);
        for(int i = 0 ; i < n ; i ++)
        {
            if(ha[i].se > ha[i + 1].se)
            {
                flag = 0 ; break;
            }
            int dis1 = ha[i + 1].fi - ha[i].fi;
            int dis2 = ha[i + 1].se - ha[i].se;
            while(dis1)
            ans += "R" , dis1 --;
            while(dis2)
            ans += 'U' , dis2 --;
        }
        if(flag)
        cout << "YES" << '\n' << ans << '\n';
        else 
        cout << "NO" << '\n';
    }
    return 0;
} 
View Code

 

 

 

C. Product of Three Numbers

題目鏈接:https://codeforces.com/contest/1294/problem/C

題意:

給你一個 n ,要求三個整數 a ,b ,c 使得 a * b * c = n 並且 a、b、c >= 2

分析:

先枚舉 n 的因子,再枚舉因子的因子即可

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n;
        cin >> n;
        int ans1 , ans2 , ans3;
        int flag = 0;
        for(int i = 2 ; i * i <= n ; i ++)
        {
            if(n % i == 0)
            {
                for(int j = 2 ; j * j < i ; j ++)
                {
                    if(i % j) continue;
                    ans1 = n / i , ans2 = j , ans3 = i / j;
                    flag = 1 ;
                    break;
                }
                int now = n / i;
                for(int j = 2 ; j * j < now ; j ++)
                {
                    if(now % j || now / j == i || j == i) continue;
                    ans1 = i , ans2 = j , ans3 = now / j;
                    flag = 1 ;
                    break;
                }
            }
        }
        if(!flag) cout << "NO" << '\n';
        else cout << "YES" << '\n' << ans1 << " " << ans2 << " " << ans3 << '\n';
    }
    return 0;
}
View Code

 

 

 

D. MEX maximizing

題目鏈接:https://codeforces.com/contest/1294/problem/D

題意:

給你 q 個詢問和 一個 x , 每次詢問輸入一個數 n ,你可以把它減任意次 x 或 加任意次 x,然后添入數組,問每次詢問結束時數組里最小的沒出現的非負整數是多少

分析:

我們可以想象有若干個長度為 x 的區間[0 , x - 1] ,那么每次詢問的數 n 只會出現在某個區間的 n % x位置上。為了滿足題目要求,我們要盡可能讓它填在比較靠前的區間里

cnt [i] 表示此次詢問時,若干個區間一共有cnt[i] 個 i 可以填到若干個區間中的 i 位置上(為了滿足題目要求,我們從第一個區間的第i個位置開始填,然后再填第二個區間第i個位置)

然后我們從第一個區間開始檢查。若到當前位置時cnt[i] != 0,則我們讓cnt[i] --(表示我們拿一個i填在這個位置上),同時往下一個位置跳,直到遇到一個沒有數可填的位置——cnt[pos] = 0

#include<bits/stdc++.h>
using namespace std;
map<int , int>cnt;
int main()
{
    int q , x , ans = 0;
    cin >> q >> x;
    while(q --)
    {
        int n;
        cin >> n;
        cnt[n % x] ++;
        while(cnt[ans % x])
        cnt[ans % x] -- , ans ++;
        cout << ans << '\n';
    }
    return 0;
}
View Code

 

 

 

E. Obtain a Permutation

題目鏈接:https://codeforces.com/contest/1294/problem/E

題意:

給你一個 n * m 的矩陣,你執行兩種操作:

① 把矩陣中任意一個元素改為任意一個數

② 把矩陣中任意一列整體往上挪一個單元格,如下圖矩陣我們對第一列向上挪了一個單元格

現要求用最少的操作次數使矩陣內每一個元素 a[i][j] = (i - 1) * m + j

分析:

因為題目只能對一列或者一個元素進行操作,所以我們逐列進行維護。

對第i行第j列的元素a[i][j] 我們假設它將成為這列的起點(第一個元素) 那么最壞的操作次數cost[i]為 i + N (把它移動到第1位需要i次 如果元素全都很奇葩需要更改N次) 

對於每一列的操作,我們先初始化cost[i] = i + N , 然后如果a[i][j]可以作為第h行的答案的答案,那么cost[h] --(把a[h][j]行設為起點的最壞操作- 1)

最后遍歷cost[1] ~ cost[n] 挑選最小的cost加到ans里即可

#include<bits/stdc++.h>
using namespace std; 
const int N = 2e5 + 10;
int main()
{
    int n , m ;
    cin >> n >> m;
    vector<vector<int>>a(n , vector<int>(m));
    for(int i = 0 ; i < n ; i ++) for(int j = 0 ; j < m ; j ++)
    {
        cin >> a[i][j];
        a[i][j] --;
    }
    int ans = 0;
    for(int j = 0 ; j < m ; j ++)
    {
        vector<int>cost(n);
        for(int i = 0 ; i < n ; i ++) cost[i] = i + n;
        for(int i = 0 ; i < n ; i ++)
        {
            if(a[i][j] % m == j && a[i][j] < n * m)
            {
                int h = i - a[i][j] / m; 
                if(h < 0) h += n;
                cost[h] --; 
            }       
        }
        ans += *min_element(cost.begin() , cost.end()); 
    }
    cout << ans << '\n';
    return 0;
}
View Code

 

 

 

F. Three Paths on a Tree

題目鏈接:https://codeforces.com/contest/1294/problem/F

題意:

給你一棵樹,要求你找出任意三點 A,B,C,使得 A~B,B~C,A~C 之間的邊最多(邊並集最大)

分析:

比賽最后幾分鍾做出來了,然而一時馬虎,提交到E題上去了。然后評測機也不給力,等賽后幾分鍾我才知道交錯題了。再放到F題上提交,一發就過了。。。

證明一組最優解中一定有兩個點是直徑的兩端點,那么題目就轉換成求樹直徑端點及與兩端點邊並集最大的點,於是就很簡單了

我們先一次bfs求出樹直徑DIS即其一端點A,再對端點A進行bfs求出另一端點B及每個點到端點A的距離dis1[i],最后再bfs端點B求出每個點到B的距離dis2[i]

最后遍歷每個點,取邊並集最大的即可(邊並集= $\dfrac {dis1\left[ i\right] +dis2\left[ i\right] -DIS}{2}+DIS$)

現在給出證明

假設某個答案取連接點x。x最遠的樹到達的點是s,根據樹的直徑算法,s是樹的某個直徑a的端點。假設x的最遠和第二遠的點組成的鏈是b,b就會和a有一段公共部分。我們取a和b相交部分距離s最遠的那個點y。那么取這個鏈上點y的答案一定比x更優  

 

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
struct Edge{
    int nex , to , w;
}edge[N];
int one , two , DIS;
int head[N] , vis[N] , d[N];
int tot = 0;
void add(int u , int v , int w)
{
    edge[tot].w = w;
    edge[tot].to = v;
    edge[tot].nex = head[u];
    head[u] = tot ++; 
}
int bfs(int st)
{
    memset(d , 0 , sizeof(d));
    memset(vis , 0 , sizeof(vis));
    queue<int>que;
    que.push(st);
    vis[st] = 1;
    int now;
    while(!que.empty())
    {
        now = que.front() , que.pop();
        for(int i = head[now] ; ~i ; i = edge[i].nex)
        {
            int TO = edge[i].to;
            if(vis[TO]) continue;    
            d[TO] = d[now] + edge[i].w;
            vis[TO] = 1;
            que.push(TO);
            if(DIS < d[TO]) DIS = d[TO]; 
        }
    }
    return now;
}
int dis1[N] , dis2[N]; 
int main()
{
    ios::sync_with_stdio(false);
    memset(head , -1 , sizeof(head)); 
    int n ;
    cin >> n;
    for(int i = 1 ; i < n ; i ++)
    {
        int x , y;
        cin >> x >> y;
        add(x , y , 1);
        add(y , x , 1);
    }
    DIS = 0;
    int one , two , three;
    one = bfs(1);
    two = bfs(one);
    for(int i = 1 ; i <= n ; i ++)
    dis1[i] = d[i];
    bfs(two);
    for(int i = 1 ; i <= n ; i ++)
    dis2[i] = d[i];
    int ans = 0;
    for(int i = 1 ; i <= n ; i ++)
    {
        if((dis1[i] + dis2[i] - DIS) / 2 + DIS > ans && i != one && i != two)
        ans = (dis1[i] + dis2[i] - DIS) / 2 + DIS , three = i;
    }
    cout << ans << '\n';
    cout << one << " " << two << " " << three << '\n';
    return 0;
}    
View Code

 

  為了更好的供人觀看,每一份代碼我都是重新手寫的,請多支持


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM