meet in the middle,适用于输入数据较小,但也没小到可以直接用暴力搜索通过的情况。
主要的思想就是讲整个搜索过程分成两半进行,最后在将这两半的结果进行合并,对于搜索复杂度为 \(O(a^b)\) 的情况,meet in the middle 可以将它优化为 \(O(a^{\frac{b}{2}})\)。
题目
P5691 [NOI2001] 方程的解数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
原来的暴力搜索复杂度是 \(150^{6}\),折半后是 \(2 \times 150^{3}\)。
//The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 10;
int n, m;
int k[N], p[N];
vector<int> sum[3];
ll qpow(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1) {
ans = ans * x;
}
y >>= 1;
x = x * x;
}
return ans;
}
void dfs(int u, ll tot, int tp) {
if (u > n) {
sum[tp].emplace_back(tot);
return ;
}
rep (i, 1, m, 1) {
dfs(u + 2, tot + 1ll * k[u] * qpow(i, p[u]), tp);
}
}
int main() {
n = read<int>(), m = read<int>();
rep (i, 1, n, 1) {
k[i] = read<ll>(), p[i] = read<ll>();
}
dfs(1, 0, 1);
dfs(2, 0, 2);
sort(sum[1].begin(), sum[1].end());
sort(sum[2].begin(), sum[2].end());
int siz1 = sum[1].size() - 1, r = sum[2].size() - 1, ans = 0;
rep (l, 0, siz1, 1) {
while (sum[2][r] + sum[1][l] > 0 && r > 0) {
-- r;
}
per (j, r, 0, 1) {
if (sum[2][j] + sum[1][l] == 0) {
++ ans;
} else {
break ;
}
}
}
cout << ans << '\n';
return 0;
}
P9234 [蓝桥杯 2023 省 A] 买瓜 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
卡常题,meet in the middle 是其中优化的一部分。
然而我并没有卡过去
//The code was written by yifan, and yifan is neutral!!!
// 并不是 AC 代码,只是提供 meet in the middle 的应用
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
typedef long double db;
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 40;
const int mod = 1e7 + 7;
using tli = tuple<ll, int>;
int n;
ll m;
ll a[N];
vector<ll> res[3];
cc_hash_table <ll, int> mp[3];
void dfs(int u, ll tot, int tp, int cnt) {
if (tot > m) return ;
if (mp[tp][tot] != 0 && cnt > mp[tp][tot]) {
return ;
}
if (u > n) {
if (mp[tp][tot] == 0) {
res[tp].emplace_back(tot);
mp[tp][tot] = cnt;
} else if (mp[tp][tot] > cnt) {
mp[tp][tot] = cnt;
}
return ;
}
dfs(u + 2, tot, tp, cnt);
dfs(u + 2, tot + a[u], tp, cnt);
dfs(u + 2, tot + a[u] / 2, tp, cnt + 1);
}
int main() {
n = read<int>(), m = read<ll>();
m <<= 1;
rep (i, 1, n, 1) {
a[i] = read<ll>();
a[i] <<= 1;
}
sort(a + 1, a + n + 1);
dfs(1, 0, 1, 0);
dfs(2, 0, 2, 0);
sort(res[1].begin(), res[1].end());
sort(res[2].begin(), res[2].end());
int siz1 = res[1].size(), siz2 = res[2].size(), r = siz2 - 1, ans = n + 1;
rep (l, 0, siz1 - 1, 1) {
while (res[1][l] + res[2][r] > m && r > 0) {
-- r;
}
if (res[1][l] + res[2][r] == m) {
ans = min(ans, mp[1][res[1][l]] + mp[2][res[2][r]]);
}
}
if (ans == n + 1) {
puts("-1");
return 0;
}
cout << ans << '\n';
return 0;
}
Wavy numbers - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题剧毒瘤!!!
十进制下最多是 \(14\) 位数,折半,前 \(7\) 位搜一搜,后 \(7\) 位搜一搜,处理出相接地方是浪顶和浪底的情况,然后二分查找位置求情况数量。
//The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const ll seven = 1e7;
const ll six = 1e6;
const ll five = 1e5;
const int UP = 2;
const int DN = 1;
using tll = pair<ll, ll>;
ll n, k;
vector<ll> base;
vector<tll> up, down;
void dfs(ll v, int pos, int res) {
if (res == 1) {
if (v % n == 0) {
-- k;
if (!k) {
cout << v << '\n';
exit(0);
}
}
base.emplace_back(v);
if (v >= six) {
if (pos == UP) {
down.emplace_back(v % n, v);
} else {
up.emplace_back(v % n, v);
}
} else if (v >= five) {
if (pos == DN) {
up.emplace_back(v % n, v);
}
}
return ;
}
if (pos != DN) {
int lim = v % 10;
rep (i, 0, lim - 1, 1) {
dfs(v * 10 + i, DN, res - 1);
}
}
if (pos != UP) {
int start = v % 10 + 1;
rep (i, start, 9, 1) {
dfs(v * 10 + i, UP, res - 1);
}
}
}
int main() {
n = read<ll>(), k = read<ll>();
rep (i, 1, 7, 1) {
rep (st, 1, 9, 1) {
dfs(st, 0, i);
}
}
sort(down.begin(), down.end());
sort(up.begin(), up.end());
for (ll it : base) {
ll need = (n - it * seven % n) % n;
if (it < 10) {
int num = lower_bound(up.begin(), up.end(), tll(need, it * six))
- lower_bound(up.begin(), up.end(), tll(need, 0ll));
if (num >= k) {
tll g = *(lower_bound(up.begin(), up.end(), tll(need, 0LL)) + k - 1);
cout << it * seven + get<1>(g) << '\n';
return 0;
}
k -= num;
int num2 = lower_bound(down.begin(), down.end(), tll(need + 1, 0LL))
- lower_bound(down.begin(), down.end(), tll(need, (it + 1) * six));
if (num2 >= k) {
cout << it * seven + get<1>(*(lower_bound(down.begin(), down.end(), tll(need, (it + 1) * six)) + k - 1)) << '\n';
return 0;
}
k -= num2;
} else {
int num = 0;
if (it / 10 % 10 < it % 10) {
num = lower_bound(up.begin(), up.end(), tll(need, it % 10 * six))
- lower_bound(up.begin(), up.end(), tll(need, 0ll));
if (num >= k) {
cout << it * seven + get<1>(*(lower_bound(up.begin(), up.end(), tll(need, 0ll)) + k - 1)) << '\n';
return 0;
}
} else {
num = lower_bound(down.begin(), down.end(), tll(need + 1, 0ll))
- lower_bound(down.begin(), down.end(), tll(need, (it % 10 + 1) * six));
if (num >= k) {
cout << it * seven + get<1>(*(lower_bound(down.begin(), down.end(), tll(need, (it % 10 + 1) * six)) + k - 1)) << '\n';
return 0;
}
}
k -= num;
}
}
puts("-1");
return 0;
}
标签:折半,ch,int,ll,up,tot,middle,tp,meet
From: https://www.cnblogs.com/yifan0305/p/17654997.html