Codeforces Round #615(Div.3)解题报告

Codeforces Round #615(Div.3)解题报告

A. Collecting Coins

注意\(n\)可能不够用的情况。

#include
using namespace std;
typedef long long ll;
int a, b, c, n;
void solve()
{
    cin >> a >> b >> c >> n;
    int mx = max(max(a, b), c);
    int mi = min(min(a, b), c);
    int s = a+b+c;
    int m = s - mx - mi;
    n -= (mx - mi);
    n -= (mx - m);
    if(n < 0){
        puts("NO");
        return;
    }
    if(n % 3 == 0) puts("YES");
    else puts("NO");
}

int main()
{
    int T = 1;
    scanf("%d", &T);
    while(T--) solve();
    return 0;
}

B. Collecting Packages

直接模拟这个过程就好了,注意字典序最小的方案。

#include
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 10;
int n;
//只能上和右

struct Node{
    int x, y;
}p[maxn];

bool cmp(Node a, Node b){
    if(a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}

void solve()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d%d", &p[i].x, &p[i].y);
    sort(p+1, p+1+n, cmp);

    for(int i = 1; i < n; i++)
    {
        if(p[i].y > p[i+1].y && p[i].x != p[i+1].x)
        {
            puts("NO");
            return;
        }
    }
    puts("YES");
    string ans = "";
    for(int i = 0; i < n; i++)
    {
        int x1 = p[i].x, y1 = p[i].y;
        int x2 = p[i+1].x, y2 = p[i+1].y;
        int d1 = x2 - x1;
        int d2 = y2 - y1;
        while(d1) ans += 'R', d1--;
        while(d2) ans += 'U', d2--;
    }
    cout << ans << endl;
}

int main()
{
    int T = 1;
    scanf("%d", &T);
    while(T--) solve();
    return 0;
}

C. Product of Three Numbers

枚举因数,看看能不能成。

#include
using namespace std;
typedef long long ll;
void solve()
{
    int n; cin >> n;
    vector ans;
    int t = n;
    for(int i = 2; i <= n/i; i++)
    {
        if(t % i == 0)
        {
            ans.push_back(i);
            t = t / i;
        }
        if(t == 1) break;
    }

    if(ans.size() == 1 || ans.size() == 0)
    {
        puts("NO");
        return;
    }

    if(ans.size() == 2)
    {
        int t = ans[0]*ans[1];
        if(n % t == 0 && n/t != ans[0] && n/t != ans[1])
        {
            puts("YES");
            printf("%d %d %d\n", ans[0], ans[1], n/t);
            return;
        }
        else
        {
            puts("NO");
            return;
        }
    }
    puts("YES");
    int t1 = ans[0], t2 = ans[1];
    int t3 = n/(t1*t2);
    printf("%d %d %d\n", t1, t2, t3);

}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--) solve();
    return 0;
}

D. MEX maximizing

根据贪心的思路我们可以发现答案一定是递增的,所以我们就直接把所有的点都减到不能减为止,然后答案可以变大的时候用他们来做贡献。

其实可以不用\(unordered\_map\),可以直接用数组来维护一下...

#include
using namespace std;
const int maxn = 4e5 + 10;
int q, x;
int main()
{
    scanf("%d%d", &q, &x);
    vector a;
    unordered_map mp;
    int ans = 0;
    while(q--)
    {
        int num;
        scanf("%d", &num);
        mp[num % x]++;
        while(mp[ans]) ans++;
        while(mp[ans%x] > 1)
        {
            mp[ans%x]--;
            ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}

E. Obtain a Permutation

题意也就是用最少的操作次数使得矩阵每个元素\(a(i,j)=(i-1)m+j\)

分析一下的话可以发现,每一列其实是独立的,所以最终答案一定是每一列的答案相加。

考虑第\(j\)列,最终第\(j\)列的元素就为\(j,j+m,j+2m,...,j+(n-1)m\)

对于给出的第\(j\)列数字,可以枚举谁作为最高位,从而来计算答案。

#include
using namespace std;
const int maxn = 2e5 + 10;
vector a[maxn], b[maxn];
int n, m;
int vis[maxn], add[maxn<<1];
int main()
{
    scanf("%d%d", &n, &m);
    int cnt = 0;
    for(int i = 1; i <= n; i++)
    {
        a[i].resize(m+1);
        b[i].resize(m+1);
        for(int j = 1; j <= m; j++)
        {
            scanf("%d", &a[i][j]);
            b[i][j] = ++cnt;
        }
    }

    long long ans = 0;
    for(int j = 1; j <= m; j++)
    {
        for(int i = 1; i <= n; i++) vis[b[i][j]] = i;
        for(int i = 1; i <= n; i++)
        {
            if(vis[a[i][j]]) //如果这个数本应该属于这个序列中
            {
                int t = vis[a[i][j]];
                if(t == i) add[1]++, add[n+1]++; //正好在位置上
                //放到该放到的位置上
                else if(i > t) add[1+i-t]++;
                else add[1+n+i-t]++;
            }
        }
        int tmp = 0, mi = n;
        //枚举开头的位置
        for(int l = 1; l <= n; l++)
        {
            tmp = add[l];
            //tmp 不需要变化的元素
            //本次需要的操作=n-不需要变化的元素+把它们shift到最高位
            mi = min(mi, n-tmp+(l-1));
        } ans += mi;
        for(int i = 1; i <= 2*n; i++) add[i] = 0;
        for(int i = 1; i <= n; i++) vis[b[i][j]] = 0;
    } cout << ans << endl;
    return 0;
}

F. Three Paths on a Tree

首先可以确定的是,其中的两个点一定在直径的两个端点上。

第三个点要怎么确定呢?

\(len(a,b)\)表示\(a\)\(b\)的距离,那么答案就是\(\frac{len(a,b)+len(b,c)+len(a,c)}{2}\)

所以我们找\(len(a,c)+len(b,c)\)最大就行了。

#include
using namespace std;
const int maxn = 2e5 + 10;
int n;
int head[maxn], nex[maxn<<1], ver[maxn<<1], edge[maxn<<1], tot;
inline void add_edge(int x, int y){
    ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
    edge[tot] = 1;
}

int vis[maxn]; 
int sum[maxn];
int bfs(int x)
{
    memset(vis, 0, sizeof(vis));
    queue q;
    q.push(x);
    int t;
    while(q.size())
    {
        t = q.front(); q.pop();
        for(int i = head[t]; i; i = nex[i])
        {
            int y = ver[i];
            if(!vis[y] && y != x)
            {
                q.push(y);
                vis[y] = vis[t] + 1;
            }
        }
    } return t; //bfs两段性保证t最远
}

int main()
{
    scanf("%d", &n);
    for(int i = 1, x, y; i <= n-1; i++)
    {
        scanf("%d%d", &x, &y);
        add_edge(x, y); add_edge(y, x);
    }

    int x = bfs(1), y = bfs(x), ans = 0, z;
    //此时的vis数组中存着每个点离x的距离
    //sum数组中存着len(x,y)+len(x,i)
    for(int i = 1; i <= n; i++)
        sum[i] = vis[y] + vis[i];
    bfs(y); //vis数组中存着每个点离y的距离
    for(int i = 1; i <= n; i++)
    {
        //sum中存着len(x,y)+len(x,i)+len(y,i)
        sum[i] += vis[i];
        if(i != x && i != y && sum[i] > ans)
        {
            ans = sum[i];
            z = i;
        }
    }
    printf("%d\n%d %d %d\n", ans/2, x, y, z);
    return 0;
}

你可能感兴趣的:(Codeforces Round #615(Div.3)解题报告)