二分

求最大/最小值 最小化最大值/最大化最小值 求第k小/大值(难)
一。最大/小值
1.牛客周赛E
一条路径上各节点的权值中最大的权值为该路径权值,求s到t所有路径中最小的权值(最小化最大值)
方法一:二分答案,若最大权值mid可以让s到t,那么r=mid-1
方法二:改造dj最短路算法

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int> e[N];
int main()
{
    int n,m,a,b,s,t;
    cin>>n>>m>>a>>b>>s>>t;
    
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    //求时差
    auto bfs=[&](int s)->vector<int>{
        queue<int> q;
        q.push(s);
        vector<int>vis(n+1);
        vector<int>w(n+1);
        vis[s]=1;
        w[s]=0;
        while(q.size()){
            int u=q.front();q.pop();
            for(auto k:e[u]){
                if(vis[k])continue;
                vis[k]=1;
                w[k]=w[u]+1;
                q.push(k);
            }
        }
        return w;
    };
    vector<int>w1=bfs(a);
    vector<int>w2=bfs(b);
    for(int i=1;i<=n;i++)w1[i]=abs(w1[i]-w2[i]);
    if(s==t){//下面的二分check不会检查能否到自身
        cout<<w1[s]<<'\n';
        return 0;
    }
    //二分检查在mid条件下s能否到t
    auto check=[&](int mid)->int{
    	if(w1[s]>mid)return 0;
        if(w1[t]>mid)return 0;
    	queue<int> q;
    	q.push(s);
    	vector<int> vis(n+1);
    	vis[s]=1;
    	while(q.size()){
    		int u=q.front();q.pop();
    		for(auto k:e[u]){
    			if(vis[k]||w1[k]>mid)continue;
    			vis[k]=1;
    			if(k==t)return 1;
    			q.push(k);
			}
		}
		return 0;
	};
	int l=w1[s],r=1e6,mid;
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid))r=mid-1;
		else l=mid+1;
	}
    cout<<l<<'\n';
    return 0;
}
点击查看代码
import sys
from collections import deque

input = sys.stdin.readline

n, m, a, b, s, t = map(int, input().split())

g = [[] for _ in range(n + 1)]

for _ in range(m):
    u, v = map(int, input().split())
    g[u].append(v)
    g[v].append(u)


# BFS求最短距离
def bfs(st):
    dis = [-1] * (n + 1)
    q = deque([st])
    dis[st] = 0

    while q:
        u = q.popleft()

        for v in g[u]:
            if dis[v] == -1:
                dis[v] = dis[u] + 1
                q.append(v)

    return dis


# 计算所有结点的时差
da = bfs(a)
db = bfs(b)

w = [abs(da[i] - db[i]) for i in range(n + 1)]


# 判断答案mid是否可行
def check(mid):
    if w[s] > mid or w[t] > mid:
        return False

    vis = [False] * (n + 1)
    q = deque([s])
    vis[s] = True

    while q:
        u = q.popleft()

        if u == t:
            return True

        for v in g[u]:
            if not vis[v] and w[v] <= mid:
                vis[v] = True
                q.append(v)

    return False


# 二分答案
l, r = 0, max(w)

while l < r:
    mid = (l + r) // 2

    if check(mid):
        r = mid
    else:
        l = mid + 1

print(l)

二。第k大/小值
1.丑数 III
丑数是可以被 a 或 b 或 c 整除的正整数,找出第 n 个丑数。
方法:利用容斥可以求某个数内含有多少丑数,利用最小式二分求第n个。

点击查看代码
class Solution:
    def nthUglyNumber(self, n: int, a: int, b: int, c: int) -> int:
        #二分+容斥
        l=1
        r=10**18
        ans=-1
        def check(mid):
            three_lcm=math.lcm(math.lcm(a,b),c)
            sum=mid//a+mid//b+mid//c-mid//math.lcm(a,b)-mid//math.lcm(a,c)-mid//math.lcm(b,c)+mid//three_lcm
            return sum>=n
        while l<=r:
            mid=(l+r)//2
            if check(mid):
                ans=mid
                r=mid-1
            else:
                l=mid+1
        return ans

2.阶乘函数后 K 个零
(1)含0数量就是质因数中2*5的个数,但2数量很多,所以就看5的个数。
(2)到5多一个0,到10多一个0...到25多两个0,到30多一个0...到125多3个0。所以一个数的阶乘末尾0的个数就是除以5+除以25+除以125...
(3)显然这是线性的,数越大,阶乘末尾含0个数只会不变或变多。所以可以二分,求阶乘含0个数<=k的最大数,再求<=k-1的最大数,利用容斥相减即=k的。

点击查看代码
class Solution:
    def preimageSizeFZF(self, k: int) -> int:
        if k==0:
            return 5
        def check(mid,x):
            sum=0
            while mid: # mid/5+mid/25+mid/125...
                sum+=mid//5
                mid//=5
            return sum<=x
        def f(x):
            l=1
            r=10**18
            while l<=r:
                mid=(l+r)//2
                if check(mid,x):
                    l=mid+1
                    ans=mid
                else:
                    r=mid-1
            return ans
        return f(k)-f(k-1)
posted @ 2026-10-22 19:14  spark_of_fire  阅读(10)  评论(0)    收藏  举报