NFLS贪心与数据结构题单笔记(未完结)

A. 奶牛飞车

image
贪心,把最慢的放前面


#include <bits/stdc++.h>
using namespace std;
constexpr int maxn = 1e6 + 10;
int n, m, d, L;
int s[maxn];
int ans = 0;
inline bool cmp(int x, int y) { return x > y; }
int main() {
    cin >> n >> m >> d >> L;
    for (int i = 1; i <= n; i++) {
        cin >> s[i];
    }
    sort(s + 1, s + 1 + n);
    int num = 0;
    for (int i = 0, j = 0; i < n; j++) {
        if (j == m)
            j = 0, num++;
        i++;
        while (s[i] - num * d < L) {
            i++;
            if (i > n) {
                cout << ans << endl;
                return 0;
            }
        }
        ans++;
    }
    cout << ans << endl;
    return 0;
}

B. 牛奶规划

Lay博士有N(1<=N<=10000)头奶牛准备吃草,每头牛都需要一个单位时间来吃草,且每一个时刻最多只能让一头牛吃草.牛i必须在小于等于di时刻才能吃草(1<=di<=10000)吃了草之后能产出gi(1<=gi<=1000)的奶.时间从t=1开始.

请帮助Lay博士求出最多能得到的牛奶数量.



按照牛奶的大小从大到小排序。

之后对于每一只奶牛,如果在他挤奶时间之前有空闲时间,则可以挤奶,否则换下一只奶牛。可以证明这样取到的牛奶量是最大的。

C. 集市班车

逛逛集市,兑兑奖品,看看节目对农夫约翰来说不算什么,可是他的奶牛们非常缺乏锻炼——如果要逛完一整天的集市,他们一定会筋疲力尽的。所以为了让奶牛们也能愉快地逛集市,约翰准备让奶牛们在集市上以车代步。但是,约翰木有钱,他租来的班车只能在集市上沿直线跑一次,而且只能停靠N 个地点(所有地点都以1到N之间的一个数字来表示)。现在奶牛们分成K 个小组,第 i 组有Mi (1 ≤ Mi ≤ N)头奶牛,他们希望从Si跑到Ti (1 ≤ Si < Ti ≤ N)。由于班车容量有限,可能载不下所有想乘车的奶牛们,此时也允许小组里的一部分奶牛分开乘坐班车。约翰经过调查得知班车的容量是C ,请你帮助约翰计划一个尽可能满足更多奶牛愿望的方案。

只有一间教室,要安排尽可能多的活动。

那么我们用一个变量t表示已安排最后一个活动的结束时间,赋初值为-1,按活动结束时间排序,依次接受,接受的时候注意判断,一定要该活动的开始时间>=上一个活动的结束时间。

说了这么多,我们来看这道题。

C的空间可以看作是共C间教室,那么我们就应该用一个数组来存储每一空间位置上奶牛的下车地点(每一间教室活动结束的时间)。贪心策略:同样按照结束时间排好,每一次上尽可能多的奶牛,上了之后,在对应空间位置上存放该奶牛的下车地点,当一只奶牛上车时,优先考虑与上一只奶牛时间点相近的(尽量使车可以坐满)

炸树

Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了火咋药,现在需要点燃M个点上的引线引爆所有的火咋药。

某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。

如果一个有火咋药的点的引线被点燃,那么这个点上的火咋药会爆火咋。

求引爆所有火咋药的最短时间。



一眼二分答案,然后统计当前答案的最小火咋药需求数,我的假做法,打了n个补丁依旧从20分一路涨到了57分,三分三分的涨,没救了。

#include <bits/stdc++.h>
using namespace std;
constexpr int maxn = 4000000;
int n, m, B;
struct edge {
    int to, next;
} e[maxn];
int cnt = 0;
int head[maxn];
int node[maxn], IN[maxn], OUT[maxn];
void addedge(int u, int v) {
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
    OUT[u]++, IN[v]++;
}
int ans = 0;
int dfs(int x, int need, int fa) {
    if (need == 0) {
        ans = B;
        return 0;
    }

    int res = 0;
    if (node[x] == 1)
        res = 1;
    else
        res = 0;

    for (int i = head[x]; i; i = e[i].next) {
        if (e[i].to != fa)
            res = max(res, dfs(e[i].to, need, x) + 1);
    }
    if (res > need) {
        ans++, res = -need;
    }
    return res;
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> node[i];
        if (node[i] == 1) {
            B++;
        }
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        addedge(u, v);
        addedge(v, u);
    }
    int l = 0, r = n;
    int mid;
    while (l < r) {
        mid = (l + r) >> 1;
        ans = 0;
        dfs(1, mid, -1);
        if (ans <= m) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    cout << l << endl;
    return 0;
}

归根到底统计答案还得用一个类似DP的东西,但是不算DP。
f[x]表示在x的子树内未被覆盖的与x距离最远的敏感词点距离,g[x]表示在x的子树内与x距离最近的点燃点距离。
如果f[x]+g[x]<=mid,那么就说明x子树内就可以搞定。
如果f[x]==mid,那么就说明x一定要被点燃。
剩下的情况就可以留给祖先处理。

漫长的征途

1、假设在能跑到的范围内,第一个价格比他便宜的加油站to,就在当前加油站加油,加到恰好能跑到to

2、在能跑到的范围内,没有价格比他便宜的加油站,就在now加满油,跑到能跑到的范围内,价格最便宜的加油站

注意,在1中不是跑到范围内最便宜的加油站,而是只要遇到一个比now便宜,就跑过去

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long

int N, G, B, D;

void read(int &x) {
    x = 0;
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
}

struct node {
    int d, p;
} e[50005];

int dis[50005], price[50005];

int findmin(int s, int lim) {
    int now = s + 1, to = 50003;
    while (now <= N) {
        if (dis[now] - dis[s] > lim)
            return to;
        if (price[now] < price[s])
            return now;
        if (price[now] < price[to])
            to = now;
        now++;
    }
    return to;
}

inline bool cmp(node a, node b) { return a.d < b.d; }

signed main() {
    cin >> N >> G >> B >> D;
    for (int i = 1; i <= N; i++) cin >> e[i].d >> e[i].p;
    sort(e + 1, e + N + 1, cmp);
    for (int i = 1; i <= N; i++) {
        dis[i] = e[i].d;
        price[i] = e[i].p;
        if (dis[i] - dis[i - 1] > G) {
            cout << "-1";
            return 0;
        }
    }
    if (dis[1] > B || D - dis[N] > G) {
        cout << "-1";
        return 0;
    }
    price[50003] = 2e9;
    int now = 0, to;
    to = findmin(now, B);
    if (now > N) {
        cout << "0";
        return 0;
    }
    now = to;
    int nowB = B - dis[to];
    int ans = 0;
    if (dis[N] == D)
        price[N] = 0;
    else {
        N++;
        dis[N] = D;
        price[N] = 0;
    }
    while (now < N) {
        to = findmin(now, G);
        if (price[to] > price[now]) {
            ans += (G - nowB) * price[now];
            nowB = G - dis[to] + dis[now];
        } else {
            ans += (dis[to] - dis[now] - nowB) * price[now];
            nowB = 0;
        }
        now = to;
    }
    cout << ans << endl;
    return 0;
}
posted @ 2024-11-20 22:01  Dreamers_Seve  阅读(10)  评论(1编辑  收藏  举报