AcWing第一场周赛题解

AcWing第一场周赛题解

A.选择数字

题目链接:AcWing 3577. 选择数字

比最大值还大的值一定不再数组中,所以直接输出两个数组的最大值即可。

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

int n, m;
int x, a, b;

int main()
{
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        cin >> x;
        a = max(a, x);
    }
    cin >> m;
    for(int i = 0; i < m; i++)
    {
        cin >> x;
        b = max(b, x);
    }

    cout << a << ' ' << b << endl;

    return 0;
}

B.最大中位数

题目链接:3578. 最大中位数

比赛的时候脑袋发抽,老是想用什么奇奇怪怪的方法做,加上刚刚学了对拍,对了一个多小时,发现暴力都写错了,菜死了。。。赛后发现,直接暴力遍历就行

首先肯定要排序的。排完序之后可以发现,从中位数开始,往后直接一个一个累加,并且一旦中位数和后面的数字相等了,就得一起同时累加,直到k无法满足将相等的数都加1为止。此时中位数即为最大中位数。(注意边界是2e9

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 2e5+10;

int n, k;
int a[N];

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> a[i];
    sort(a, a + n);
    int p = n / 2;
    a[n] = 2e9+10;
    for(int i = p + 1; i <= n && k; i++)
    {
    	if(i - p <= k) 
    	{
    	    int t = a[i] - a[p];
    	    a[p] += min(t, k / (i - p)), k -= (i - p) * t;
    	}
    	else k = 0;
    }
	cout << a[p] << endl;
    
    return 0;
}

法二:二分

同样,我们只需要对排完后,中位数及其后面数进行操作。可以二分答案mid,将后半段小于mid的全部加到mid,然后判断操作是否小于k。二分出满足条件的最大值,即为最终答案。

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 2e5+10;

int n, k;
int a[N];

bool check(int p)
{
    LL sum = 0;
    for(int i = n / 2; i < n; i++)
        if(a[i] < p) sum += p - a[i];
    if(sum > k) return false;
    else return true;
}

int main()
{
    cin >> n >> k;
    for(int i = 0; i < n; i++) cin >> a[i];
    sort(a, a + n);
    
    int l = 0, r = 2e9;
    while(l < r)
    {
        int mid = (LL)l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
	cout << l << endl;
    
    return 0;
}

C.数字移动

题目链接:3579. 数字移动

经过分析可以发现,如果将每一个数字看成一个顶点,可以移动看成一条有向边,则可以构成一个有向图。而且该有向图中,每一个顶点只有一条出边和一条入边。可以回到自己原本位置的路经一定是一个简单环。由此可以得出做法:求该图的所有强连通分量,答案即为所在强连通分量的点的数目。

进一步分析可以发现,所有的环可以看成一个集合,每一个数字需要的操作次数即为所在集合的大小。所以可以用维护集合大小的并查集做。

AC代码:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 2e5+10;

int t, n;
int p[N], s[N];

int find(int x)
{
    if(p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    cin >> t;
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) p[i] = i, s[i] = 1;
        for(int j = 1; j <= n; j++)
        {
            int x;
            scanf("%d", &x);
            if(find(j) != find(x))
            {
                s[find(j)] += s[find(x)];
                p[find(x)] = p[find(j)];
            }
        }
        for(int i = 1; i <= n; i++)
            printf("%d ", s[find(i)]);
        puts("");
    }
    
    return 0;
}
posted @ 2021-05-29 21:39  四谷夕雨  阅读(66)  评论(0编辑  收藏  举报