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
个长度为4
的01
串,其中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
若题目修改为:有多少个满足 条件(-) 的长度为n
的01
串。
条件(-):若使用最少划分将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 1≤n≤100
输入
第一行一个整数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
。