Topcoder SRM 726 Hard

链接:

link

题意:

N 个任务,可以在[starti,finishi]这段时间内完成,完成了能获得 costi 的收益,每个时间最多完成一个任务,问最大收益。

题解:

不难发现这是个拟阵,所以可以从大到小排序之后贪心。

考虑对于一组区间,如何判断它是否合法也可以贪心:从左到右扫,每个位置安排 r 最小的点,记为ri,如果不存在 ri=

考虑插入一个区间 [x,x] 是否合法,考虑 i [i+1,ri]连边,如果能换那么 x 一定能到达

举个例子, xyz 的意义就是 x 这个位置放了一个区间,所以原来x这个位置放的区间要调整到 y ,同理y要调整到 z ,由于z上面没有放区间,所以就不用调整了。

每次放完一个区间之后暴力算出哪些合法,用 set 维护一下就好了,详见代码。

复杂度 O(nlogm+m2logm) ,其中 m=max(finishi)

代码:

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;

const int MAXN = 2005;
const int mod = 1e9 + 7;

class HeroicSchedule
{
    int m, ans, rig[MAXN];
    vector <int> r[MAXN];
    vector <pii> a[MAXN];
    set <int> s;

    inline void Solve()
    {
        s.clear();
        multiset <int> cur;
        for (int i = 0; i < m; i ++)
        {
            for (auto j : r[i])
                cur.insert(j);
            if (cur.empty())
                rig[i] = m;
            else
                rig[i] = *cur.begin(), cur.erase(cur.begin());
        }
        for (int i = m - 1; ~i; i --)
            if (rig[i] == m || (!s.empty() && *s.begin() <= rig[i]))
                s.insert(i);
    }

    public:
        int getmax(int n, int A, int B, int C, int modStart, int modLen, int modCost)
        {
            ans = 0;
            for (int i = 1, x = A, y, z; i <= n; i ++, x = (1LL * z * B + C) % mod)
                y = (1LL * x * B + C) % mod, z = (1LL * y * B + C) % mod, a[z % modCost].pb(mp(x % modStart, y % modLen + x % modStart));
            m = modStart + modLen - 1;
            for (int i = 0; i < m; i ++)
                s.insert(i);
            for (int i = modCost - 1; i; i --)
                for (auto e : a[i])
                    if (!s.empty() && *s.rbegin() >= e.xx && *s.lower_bound(e.xx) <= e.yy)
                        ans += i, r[e.xx].pb(e.yy), Solve();
            return ans;
        }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值