一篇题解

# [AGC018B] Sports Festival

# 题面翻译

Takahashi 举办了一场运动会,这场运动会有 MM 个项目,有 NN 个人来参加。

每个人会在所有开展的项目当中,选择她心目中排名最高的那个项目参加。

因此,如果开展全部项目的话,可能某个项目的人数会爆多无比,所以 Takahashi 决定,只开展其中的一部分项目,使得参加人数最多的那个项目,参加人数尽量少。

请输出这个值。

———from@__stdcall

# 分析

首先对于这 mm 个赛事,我们可以一开始都选上,然后我们考虑怎么会让答案变的更优,既然我们要满足最大值最小,那么一个比较显然的想法就是我们每次删去参加人数最多的比赛,然后这个答案一定是不会变的更劣的,因为我们只改动了一个项目,只会发生两种情况

①:对于所有的涉及到改动的人在删掉当前的活动后,如果下一个优先级的活动都一样,那么答案是跟删之前相等的。

②:如果他们的下一个优先级的活动不一样,那么最大值一定是比之前小。

所以这么贪心一定是对的,同时我们对于每个活动删还是不删,一定都是删去的是当前位置之后的位置,那么每个人选择的活动一定是往后走的,然后按照上面的贪心策略删就行了。

#include <cstring>
#include <iostream>
#include <algorithm>
namespace read_write
{
    template <typename T>
    inline void read(T &x)
    {
        x = 0;
        T f = 1;
        char ch = getchar();
        while (ch > '9' || ch < '0')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
            x = x * 10 + ch - '0', ch = getchar();
        x *= f;
        return;
    }
    template <typename T, typename... Args>
    inline void read(T &first, Args &...args)
    {
        read(first);
        read(args...);
    }
    template <typename T>
    inline void write(T x)
    {
        if (x < 0)
        {
            x = -x;
            putchar('-');
        }
        if (x > 9)
            write(x / 10);
        putchar(x % 10 + '0');
    }
    template <typename T>
    T max(T x, T y)
    {
        return x > y ? x : y;
    }
    template <typename T>
    T min(T x, T y)
    {
        return x > y ? y : x;
    }
    template <typename T>
    void swap(T &a, T &b)
    {
        T tem = b;
        b = a;
        a = tem;
    }
}
namespace Solve
{
    using namespace read_write;
    const int N = 520;
    int n, m, ans;
    int a[N][N];
    int cnt[N], cur[N];
    bool st[N];
    void solve()
    {
        read(n, m);
        for(int i = 1 ; i <= m ; ++ i)  // 一开始将所有的活动选上
            st[i] = true;
        for(int i = 1 ; i <= n ; ++ i)
        {
            for(int j = 1 ; j <= m ; ++ j)
                read(a[i][j]);
            cur[i] = 1;
            ++ cnt[a[i][1]];   // 记录每个活动参加的人数
        }
        ans = n;
        for(int k = 1 ; k <= m ; ++ k)
        {
            int mx = -1, pos = 0;
            for(int i = 1 ; i <= m ; ++ i)    // 找到当前的最大值和是哪个活动
                if(st[i] && cnt[i] > mx)
                    mx = cnt[i], pos = i;
            ans = min(ans, mx);   // 更新一下答案
            st[pos] = false;   // 删去这个活动
            for(int i = 1 ; i <= n ; ++ i)  // 更新有影响的人的选择的活动
            {
                if(a[i][cur[i]] == pos)
                {
                    while(cur[i] < m && !st[a[i][cur[i]]])
                        ++ cur[i];
                    ++ cnt[a[i][cur[i]]];
                }
            }
        }
        write(ans);
    }
}
int main()
{
    Solve :: solve();
    return 0;
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Tokai Teio 微信支付

微信支付

Tokai Teio 支付宝

支付宝

Tokai Teio 贝宝

贝宝