ICPC2023网络赛第二场补题

M.Find the Easiest Problem

思路

签到题,可以用多个 set 维护一下每个题的通过数量。

代码

void solve(void) {
    int n; std::cin >> n;
    std::vector<int> book(27);
    std::set<std::string> S[27];
    for(int i = 1; i <= n; i++) {
        std::string a, c; 
        char b;
        std::cin >> a >> b >> c;
        if(c == "accepted") {
            if(!S[b - 'A'].count(a)) {
                S[b - 'A'].insert(a);
                book[b - 'A']++;
            }
        }
    }
    int maxn = 0;
    char ans = 0;
    for(int i = 0; i <= 26; i++) {
        if(book[i] > maxn) {
            maxn = book[i];
            ans = char(i + 'A');
        }
    }
    std::cout << ans << '\n';
}

A.World Cup

思路

列出中国队当前的实力排名,考虑最优情况然后输出。

代码

void solve(void) {
    std::vector<int> a(33);
    for(int i = 1; i <= 32; i++) std::cin >> a[i];
    int cnt = 0;
    for(int i = 2; i <= 32; i++) if(a[i] < a[1]) cnt++;
    if(cnt >= 31) {
        std::cout << "1\n";
    } else if(cnt >= 27) {
        std::cout << "2\n";
    } else if(cnt >= 13) {
        std::cout << "4\n";
    } else if(cnt >= 6) {
        std::cout << "8\n";
    } else if(cnt >= 2) {
        std::cout << "16\n";
    } else std::cout << "32\n";
}

F.Make Max

思路

要想最大化操作次数,应该让小的优先变成比它大的,再统一变成比它更大的。这个过程可以用单调栈维护。第一次从左往右找,第二次从右往左找。需要注意的是维护的是不增单调栈,第一次从左往右时已经处理过等于的情况了,从右往左时要跳过。

代码

void solve(void) {
    int n; std::cin >> n;
    std::vector<int> a(n + 2);
    a[0] = a[n + 1] = INF;
    for(int i = 1; i <= n; i++) std::cin >> a[i];
    std::stack<int> s;
    s.push(0);
    i64 ans = 0;
    for(int i = 1; i <= n; i++) {
        while(s.size() && a[s.top()] < a[i]) s.pop();
        ans += i - s.top() - 1; 
        s.push(i);
    }
    while(s.size()) s.pop();
    s.push(n + 1);
    for(int i = n; i >= 1; i--) {
        while(s.size() && a[s.top()] < a[i]) s.pop();
        if(s.size() && a[s.top()] != a[i]) ans += s.top() - i - 1;
        s.push(i);
    }
    std::cout << ans << '\n';
}

G.the Median of the Median of the Median

思路

对于中位数问题,可以用二分答案,每次将大于 \(mid\) 的数设置为 \(1\),小于 \(mid\) 的数设置为 \(-1\) ,这样判断当前 \(mid\) 是否大于等于中位数就转化为了判断数组的和是否大于等于 \(0\) 。在此基础上由于我们要判断中位数的中位数,所以用二维前缀和判断每个区间的中位数是否合法。

代码

int s1[N][N];
int s[N], b[N][N];
void solve(void) {
    int n; std::cin >> n;
    std::vector<i64> a(n + 1);
    for(int i = 1; i <= n; i++) std::cin >> a[i];
    i64 l = 0, r = *std::max_element(a.begin(), a.end()), ans = 0;
    auto check = [&](i64 x) -> bool {
        s[0] = 0;
        for(int i = 1; i <= n; i++) {
            int num = (a[i] <= x ? 1 : -1);
            s[i] = s[i - 1] + num;
        }
        for(int i = 1; i <= n; i++) {
            for(int j = i; j <= n; j++) {
                b[i][j] = (s[j] - s[i - 1] >= 0 ? 1 : - 1);
            }
        }
        for(int i = 1; i <= n; i++) 
            for(int j = 1; j <= n; j++) 
                s1[i][j] = s1[i - 1][j] + s1[i][j - 1] - s1[i - 1][j - 1] + b[i][j];
        int sum = 0;
        for(int i = 1; i <= n; i++) {
            for(int j = i; j <= n; j++) {
                int c = (s1[j][j] - s1[i - 1][j] - s1[j][i - 1] + s1[i - 1][i - 1] >= 0 ? 1 : -1);
                sum += c;
            }
        }
        return sum >= 0;
    };
    while(l <= r) {
        i64 mid = (l + r) / 2;
        if(check(mid)) {
            r = mid - 1;
            ans = mid;
        } else l = mid + 1;
    }
    std::cout << ans;
}
posted @ 2025-08-28 17:10  dbywsc  阅读(35)  评论(0)    收藏  举报