洛谷100题计划 (15/100)

洛谷100题计划 (15/100)

P1094 [NOIP2007 普及组] 纪念品分组 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

要使得分组最少,其实就是要让一个大的和一个小的放一起,如果大的和小的一起放超过了\(w\),那大的就应该单独放,所以排完序之后,我们可以用双指针从两边寻找可以放一起的纪念品即可

#include<bits/stdc++.h>

using i64 = long long;

using namespace std;

typedef pair<i64, i64> PII;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int w, n;
    cin >> w >> n;
    vector<int> a(n);
    int ans = 0;
    for (auto &i : a) cin >> i;

    sort(a.begin(), a.end());

    for (int i = 0, j = n - 1; i <= j;) {
        if (a[j] + a[i] > w) {
            ans ++;
            j--;
        } else {
            ans++;
            j --, i ++;
        }
    }

    cout << ans << '\n';

    return 0;
}

P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

考虑\(A- B=C\),如果直接暴力两重\(for\)循环\(\mathcal{O}(n^2)\)肯定是要超时的,我们稍微转换一下这个式子就可以得到\(A=B+C\),如果我们能知道\(B+C\)的个数(记为\(num_{B+C}\),\(A\)的个数(记为\(num_A\)),那么\(A=B+C\)的数对个数不就等于\(num_{B+C} \times num_A\)了吗,当然你也可以提前用一个数列把\(B+C\)算出来,不过我这里推荐用\(map\),\(map\)内置的\(find\)函数复杂度是\(\mathcal{O}(logn)\)的,且不用担心空间开太大的问题,这样总复杂度就是\(\mathcal{O}(nlogn)\)

#include<bits/stdc++.h>

using i64 = long long;

using namespace std;

typedef pair<i64, i64> PII;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    map<int, i64> mp;
    int c, m, n;
    cin >> n >> c;
    vector<int> a(n);
    for (int i = 0; i < n; i ++) {
        cin >> m;
        mp[m]++;
    }
    i64 ans = 0;
    for (auto [i, j] : mp) {
        if (mp.find(i + c) != mp.end()) {
            ans += j * mp[i + c];
        }
    }
    cout << ans << endl;

    return 0;
}

P1105 平台 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

惹,实话实说,被这题ex到了感觉是这题的描述不太清楚,看了半天讨论区才改对

首先就是,我是先记录四个信息,该平台序号(\(id\)),高度(\(H\)),左边界(\(L\))和右边界(\(R\)),然后按高度排序,高度相同的情况下一定要把大的排前面,,这样后面第一次往前找到的平台才会是序号较小的平台,剩下就是去找到对应的平台,然后从这个平台往前面找,我们要找的这个平台高度相同的可以直接跳过,找到之后直接退出

代码可能有一点长,但主要是理解那个思维

#include<bits/stdc++.h>

using i64 = long long;

using namespace std;

typedef pair<i64, i64> PII;

struct Node {
    int id, H, L, R;
    Node(int i, int h, int l, int r): id(i), H(h), L(l), R(r) {};
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<Node> a;
    for (int i = 1; i <= n; i ++) {
        int h, l, r;
        cin >> h >> l >> r;
        a.emplace_back(i, h, l, r);
    }

    sort(a.begin(), a.end(), [](Node x, Node y) {
        if (x.H == y.H) return x.id > y.id;
        return x.H < y.H;
    });

    for (int  i = 1; i <= n; i ++) {
        int pos = 0;
        for (int j = 0; j < n; j ++) {
            if (a[j].id == i) {
                pos = j;
                break;
            }
        }

        int ansL = 0, ansR = 0;
        for (int j = pos; j >= 0; j --) {
            if(a[j].H == a[pos].H) continue;
            if (a[pos].L > a[j].L && a[pos].L < a[j].R) {
                ansL = a[j].id;
                break;
            }
        }
        for (int j = pos; j >= 0; j --) {
            if(a[j].H == a[pos].H) continue;
            if (a[pos].R > a[j].L && a[pos].R < a[j].R) {
                ansR = a[j].id;
                break;
            }
        }
        cout << ansL << ' ' << ansR << '\n';
    }

    return 0;
}

P1111 修复公路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

以前写过的直接上代码了

采用并查集的思路,先把所有路按照时间的顺序排序,然后每建一条路就把两个村庄连起来,然后\(n-1\),当\(n=1\)时,说明所有的村庄都被一个村庄连起来,此时任意两个村庄都能通车,输出此时的时间即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int id[N];
int n, m, p;
struct Edge {
    int x, y, t;
} edge[N];
int find(int k) {
    if (id[k] == k) return k;
    return id[k] = find(id[k]);
}
bool cmp(struct Edge a, struct Edge b) {
    return a.t < b.t ;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n >> m ;
    for (int i = 1; i <= n; i++)
        id[i] = i;
    int z, x, y;
    for (int i = 0; i < m; i++)
        cin >> edge[i].x >> edge[i].y >> edge[i].t ;

    sort(edge, edge + m, cmp);

    for (int i = 0; i < m; i++) {
        if (find(edge[i].x ) != find(edge[i].y )) {
            id[find(edge[i].x)] = find(edge[i].y);
            n--;
        }
        if (n == 1) {
            cout << edge[i].t << endl;
            break;
        }
    }
    if (n != 1) cout << "-1\n" ;
    return 0;
}

P1115 最大子段和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

考虑\(dp[i]\)表示为过去一个子段当前点的最大值,所以得出转移方程\(dp[i] = max(dp[i -1]+a[i],a[i])\),如果过去的加上现在的还更小了,那我们直接就断掉前面的,又从当前点新开一个段

#include<bits/stdc++.h>

using i64 = long long;

using namespace std;

typedef pair<i64, i64> PII;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<i64> a(n + 1);
    for(int i = 1;i <= n;i ++) 
        cin >> a[i];

    a[0] = INT_MIN;
    vector<i64> dp(n + 1,INT_MIN);
    for(int i = 1;i <= n;i ++){
        dp[i] = max(dp[i - 1] + a[i], a[i]);
    }

    i64 ans = *max_element(dp.begin() + 1, dp.end());
    cout << ans << '\n';

    return 0;
}
posted @ 2023-08-24 18:46  Ke_scholar  阅读(8)  评论(0编辑  收藏  举报