2022-6-4 最小距离最大,二进制数字,平衡环

1. 最小距离最大 [二分]

给出n个位置(数轴上的坐标值),从中选出k个,让这k个位置相邻两个之间的距离(相邻位置坐标的差值)尽可能的大(尽可能大的意思是这k-1个距离的最小值尽量大)。输出这个最大的最小值。

输入

第一行:2个数n和k(2 <= n <= 100000, 2 <= k <= 10000, k <= n)
后面n行:每行一个数Pi,表示具体位置(0 <= Pi <= 10^9),位置是无序的。

输出

输出一个数,对应最大的距离。

输入样例

5 3
1
3
5
7
9

输出样例

4
解释:选位置:1 5 9。

代码

#include<bits/stdc++.h>

using namespace std;

int n, k, pos[100005];

bool check(int x) {
    int ans = 1;
    for (int i = 0, prev = 0; i < n; ++i) {
        if (pos[i] - pos[prev] >= x) {
            ans++;
            prev = i;
        }
    }
    return ans >= k;
}

int main() {
    cin >> n >> k;
    for (int i = 0; i < n; ++i) cin >> pos[i];
    sort(pos, pos + n);
    int lo = 0, hi = 1000000005;
    while (lo < hi) {
        int mi = lo + ((hi - lo) >> 1);
        check(mi) ? lo = mi + 1 : hi = mi;
    }
    cout << --lo;
    return 0;
}

2. 二进制数字 [动态规划]

有多少个长度为n的二进制串,既不存在3个连续的1,也不存在3个连续的0

例如n = 4,共有16个长度为401串,其中0000 0001 1000 1111 0111 1110,不符合要求,所以共有10个符合要求的串。

输入

输入共1个数n(1 <= n <= 100000)

输出

输出结果mod 1e9+7

输入样例

4

输出样例

10

代码 1 [斐波那契]

#include<bits/stdc++.h>

using namespace std;
const int mod = 1e9 + 7;

int main() {
    int n;
    cin >> n;
    long long f = 0, g = 1;
    while (n--) {
        g += f % mod;
        f = (g - f) % mod;
    }
    cout << 2 * g % mod;

    return 0;
}

代码 2

若题目修改为:有多少个满足 条件(-) 的长度为n01串。

条件(-):若使用最少划分将01串划分为仅包含0(或1)的连续子序列,不存在长度为3的子序列。

#include<bits/stdc++.h>

using namespace std;
using ull = unsigned long long;

ull dp[100005][8];

// 对于 长度为 i 的01串 dp[i][j]
// dp[i][0] - 以   1 个 0 结尾的01串
// dp[i][1] - 以   2 个 0 结尾的01串
// dp[i][2] - 以   3 个 0 结尾的01串
// dp[i][3] - 以 >=4 个 0 结尾的01串
// dp[i][4] - 以   1 个 1 结尾的01串
// dp[i][5] - 以   2 个 1 结尾的01串
// dp[i][6] - 以   3 个 1 结尾的01串
// dp[i][7] - 以 >=4 个 1 结尾的01串

int main() {
    int n;
    cin >> n;
    dp[1][0] = dp[1][4] = 1;
    for (int i = 2; i <= n; ++i) {
        dp[i][0] = dp[i - 1][4] + dp[i - 1][5] + dp[i - 1][7];
        dp[i][1] = dp[i - 1][0];
        dp[i][2] = dp[i - 1][1];
        dp[i][3] = dp[i - 1][2] + dp[i - 1][3];
        dp[i][4] = dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][3];
        dp[i][5] = dp[i - 1][4];
        dp[i][6] = dp[i - 1][5];
        dp[i][7] = dp[i - 1][6] + dp[i - 1][7];
    }
    cout << dp[n][0] + dp[n][1] + dp[n][3] + dp[n][4] + dp[n][5] + dp[n][7];
    return 0;
}

3. 平衡环 [拓扑]

给定一棵 n n n个点的树,每条边有一个边权,边权只可能是 4 4 4 7 7 7。你想在树上选择两个没有直接连边的点,并在这两点间加一条边权为 4 4 4 7 7 7的连边。很显然,树上出现一个环,如果这个环上边权为 4 4 4的边数与边权为 7 7 7的边数相等,那么这个环是一个平衡环。你希望得到这样一个平衡环,请问需要连接哪两个点,并赋予什么边权。

如果有多种方案,输出任意一组解即可。如果无解,输出 − 1 -1 1

数据范围 1 ≤ n ≤ 100 1 \leq n \leq 100 1n100

输入

第一行一个整数n,表示树中节点数。 接下来n-1行,每行三个数u, v, w,表示u,v两点间连有一条权值为w的边,w只可能是4或7

输出

输出仅一行,包括三个整数u, v, w,表示你将u,v两节点用权值为w的边连接,形成一个平衡环。 要求u, v在树中不存在连边。 如果无解,输出-1。

输入样例

5
1 2 4
3 2 7
2 4 4
4 5 7

输出样例

1 5 7

代码

#include<bits/stdc++.h>

using namespace std;

int n, xx, yy, vv;
unordered_map<int, int> edge[101], graph[101]; // edge用于距离计算, graph保留原始数据
bool visited[101];

bool generateParent(int node, list<int> &result) {
    result.clear();
    result.push_back(node);
    edge[node][node] = 0;
    visited[node] = true;
    if (graph[node].size() == 1 && visited[graph[node].begin()->first]) return false; // 叶子节点

    auto generateDistance = [&](list<int> &a, int pilot) -> void { // 计算 node 的后代与 node 的距离
        for (int i:a) {
            edge[node][i] = edge[node][pilot] + edge[pilot][i];
        }
    };

    auto check = [&](list<int> &a1, list<int> &a2) -> bool {
        for (int i:a1) {
            for (int j:a2) {
                if (graph[i].count(j)) continue; // 排除两节点直接相连的情况
                if (abs(edge[node][i] + edge[node][j]) == 1) {
                    xx = i, yy = j, vv = (edge[node][i] + edge[node][j] == 1 ? 7 : 4);
                    return true;
                }
            }
        }
        return false;
    };

    list<int> instance;
    for (auto&[x, y]:edge[node]) {
        if (visited[x]) continue; // 已访问节点必为当前节点父节点
        if (generateParent(x, instance)) return true; // DFS - 孩子
        generateDistance(instance, x); // 更新公共祖先到后代的距离
        if (check(result, instance)) return true; // 检查是否有满足题意的值
        result.splice(result.end(), move(instance));
    }
    return false;
}

int main() {
    cin >> n;
    for (int i = 1, x, y, val; i < n; ++i) {
        cin >> x >> y >> val;
        graph[x][y] = graph[y][x] = edge[x][y] = edge[y][x] = (val == 4 ? 1 : -1);
    }
    list<int> temporary;
    if (generateParent(1, temporary)) {
        cout << xx << ' ' << yy << ' ' << vv;
    } else {
        cout << -1;
    }

    return 0;
}

题单来源:QQ群200162761

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值