首页 > 其他分享 >「学习笔记」meet in the middle(折半搜索)

「学习笔记」meet in the middle(折半搜索)

时间:2023-08-24 19:56:00浏览次数:45  
标签:折半 ch int ll up tot middle tp meet

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

相关文章

  • 二分查找法(折半查找)
    二分查找法是一种在有序数组中查找特定元素的算法。为了理解它的工作原理,我们需要知道数组是有序的,也就是说,数组中的元素按照升序或降序排列。二分查找法的基本步骤如下:选择数组的中间元素。如果中间元素正好是目标值,则搜索结束。如果目标值大于中间元素,则只需在数组的......
  • OpenHarmony Meetup 广州站 OpenHarmony正当时—技术开源
     招募令 OpenHarmony Meetup 广州站 火热招募中,等待激情四射的开发者,线下参与OpenHarmonyMeetup线下交流 展示前沿技术、探讨未来可能、让你了解更多专属OpenHarmony的魅力 线下参与,先到先得,仅限20个名额! 报名截止时间8月23日24:00点 1、可获得惊喜开发......
  • KubeSphere 社区双周报 | 本周六上海站 Meetup 准时开启 | 2023.7.21-08.03
    KubeSphere社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过commit的贡献者,并对近期重要的PR进行解析,同时还包含了线上/线下活动和布道推广等一系列社区动态。本次双周报涵盖时间为:2023.07.21-2023.08.04。贡献者名单新晋KubeSphereCon......
  • .Net Core MiddleWare
    目录作用Use第一种第二种UseMiddleWareCustomMiddleWare.csProgram.csMapMapWhen作用中间件是一种装配到应用管道以处理请求和响应的软件。每个组件:选择是否将请求传递到管道中的下一个组件。可在管道中的下一个组件前后执行工作。请求委托用于生成请求管道。请求委托......
  • 配置 Forwarded Headers Middleware
    来自微软的说明:ConfigureASP.NETCoretoworkwithproxyserversandloadbalancers|MicrosoftLearn。通过该中间件,会更新:HttpContext.Connection.RemoteIpAddress:使用 X-Forwarded-For 请求头的值.其它的配置会影响到中间件如何设置 RemoteIpAddress的值.消费......
  • ​来,一起搞AV,LiveVideoStack Meet再启动
    作者 |包研上周,大师兄的一篇《近期对流媒体技术的思考》道出了多媒体技术圈的现状,一句“如果你身边有一个从事音视频技术开发的朋友、同事,请珍惜和他的友谊,因为他对音视频技术确实是真爱,而且是深爱的那种”戳中了内心,一时语塞。从2017年发出第一篇公众号文章(3月10日),到第一个公开......
  • 华为云第二期线下meetup·北理工站圆满落幕
    7月28日,华为云开源团队受邀在北京理工大学举办第二期线下meetup,此次活动从“了解开源和前沿开源技术分享”出发,帮助高校学生了解开源,参与开源,同时通过技术分享与现场实操帮助高校学生加强对前沿开源技术的了解。在本次活动中,我们邀请了开放原子开源基金会专家郭皓为参会学生们做了......
  • 立即报名 | AI +Serverless Meetup 上海站 8 月 5 日等你相约!
    自2021年5月后,KubeSphere社区与上海的各位小伙伴已阔别两年,许久不见,甚是想念!2023年8月5日,KubeSphere社区将走进上海组织一场主题为“AI+Serverless”的Meetup。此外,云原生也依旧是本次Meetup的分享和交流话题。此次Meetup,我们邀请到了亚马逊云科技、驭势科技......
  • 3-1 在上面有关折半查找的例子中,while 循环语句内共执行了两次测试,其实 只要一次就足
    ArchlinuxGCC13.1.1 202304292023-07-2911:07:02星期六 点击查看代码#include<stdio.h>intbinsearch(intx,intv[],intn){intlow,high,mid;low=0;high=n-1;mid=(low+high)/2;while((low<=high)&&(......
  • ASP.NET Core 授权中间件 AuthorizationMiddleware
    ///<summary>///Amiddlewarethatenablesauthorizationcapabilities.///</summary>publicclassAuthorizationMiddleware{//AppContextswitchusedtocontrolwhetherHttpContextorendpointispassedasaresourcetoAuthZ......