zoukankan      html  css  js  c++  java
  • Codeforces 1132C

    题目链接:https://codeforces.com/contest/1132/problem/C

    题意:

    栅栏有 $n$ 个节,有 $q$ 个人可以雇佣来涂栅栏,第 $i$ 个人可以涂第 $l_i$ 节到第 $r_i$ 节。

    但是现在预算紧张,所以只能雇佣 $q-2$ 个人,你想确认雇佣哪 $q-2$ 个人使得涂色栅栏的节数最大。

    题解:

    首先看到 $n$ 的范围,就可以想到大概可以枚举第一个不雇佣的人再枚举第二个不雇佣的人,时间复杂度在 $O(n^2)$ 左右。

    先假定第一个不雇佣的人是第 $x$ 个人,然后剩下的 $q-1$ 个人,他们的涂栅栏情况用数组 $c$ 记录,$c_i$ 表示第 $i$ 节有多少人涂。

    然后我们用另一个数组 $d$ 对应到数组 $c$,若 $c_i = 1$,则 $d_i = 1$;否则 $d_i = 0$。这样一来就能对每个人,用前缀和优化 $O(1)$ 地求出仅他能涂的栅栏节数。

    这样,我们用数组 $c$ 所有 $c_i > 0$ 的 $i$ 的数目减去仅这个人能涂抹的节数,就知道最终能涂多少节。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> P;
    #define mk(x,y) make_pair(x,y)
    #define fi first
    #define se second
    const int maxn=5e3+10;
    int n,q;
    P p[maxn];
    int cnt[maxn],sum[maxn];
    int main()
    {
        cin>>n>>q;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=q;i++)
        {
            cin>>p[i].fi>>p[i].se;
            for(int k=p[i].fi;k<=p[i].se;k++) cnt[k]++;
        }
    
        int ans=0;
        for(int x=1;x<=q;x++)
        {
            for(int k=p[x].fi;k<=p[x].se;k++) cnt[k]--;
    
            int tot=0;
            for(int k=1;k<=n;k++)
            {
                tot+=(cnt[k]>0);
                if(cnt[k]==1) sum[k]=1;
                else sum[k]=0;
                sum[k]+=sum[k-1];
            }
    
            int Max=0;
            for(int y=1;y<=q;y++)
            {
                if(x==y) continue;
                Max=max(Max,tot-(sum[p[y].se]-sum[p[y].fi-1]));
            }
            ans=max(ans,Max);
    
            for(int k=p[x].fi;k<=p[x].se;k++) cnt[k]++;
        }
    
        cout<<ans<<endl;
    }
  • 相关阅读:
    原型模式——浅复制与深复制
    初识Java反射
    建造者模式
    利用事件委托弥补观察者模式不足
    利用Java提供的Observer接口和Observable类实现观察者模式
    观察者模式
    再说单例模式的线程安全问题
    组合模式
    MyBatis3入门
    [Swift]LeetCode1216. 验证回文字符串 III | Valid Palindrome III
  • 原文地址:https://www.cnblogs.com/dilthey/p/10489056.html
Copyright © 2011-2022 走看看