2025-09-13

47 阅读4分钟

acwing 树的范围(二分模板题)

题意:给定n个树,非严格升序,求给定数字k的坐标范围 错因

  • 要分别求两种二分,judge部分的不等号弄反了
  • 忽略答案要求坐标从零开始
  • N设置的略小,没通过所有样例

错误代码(欢迎debug)

#include<bits/stdc++.h>
using namespace std;

const int N = 10010;

int a[N];
int n;
int bl(int k){
    int l = 1,r = n;
    while(l<r){
        int mid = (l+r)/2;//寻找左边界,向左取整
        if(a[mid]<=k) r = mid;
        else l = mid+1;
    }
    if(l == r)return l;
    else return -1;
}
int br(int k){
    int l = 1,r = n;
    while(l<r){
        int mid = (l+r+1)/2;
        if(a[mid]>=k) l = mid;
        else r = mid-1;
    }
    if(l == r)return l;
    else return -1;
}
int main(){
    int q;
    cin>>n>>q;
    for(int i = 1;i<=n;i++)cin>>a[i];
    while(q--){
        int k;
        cin>>k;
        cout<<bl(k)<<" "<<br(k)<<endl;
    }
    return 0;
}

修改代码

#include<bits/stdc++.h>
using namespace std;

const int N = 100100;

int a[N];
int n;
int bl(int k){
    int l = 0,r = n-1;
    while(l<r){
        int mid = (l+r)/2;//寻找左边界,向左取整
        if(a[mid]>=k) r = mid;
        else l = mid+1;
    }
    return (a[l] == k)?l:-1;
}
int br(int k){
    int l = 0,r = n-1;
    while(l<r){
        int mid = (l+r+1)/2;
        if(a[mid]<=k) l = mid;
        else r = mid-1;
    }
    return (a[l] == k)?l:-1;
}
int main(){
    int q;
    cin>>n>>q;
    for(int i = 0;i<n;i++)cin>>a[i];
    while(q--){
        int k;
        cin>>k;
        cout<<bl(k)<<" "<<br(k)<<endl;
    }
    return 0;
}

acwing 790 (浮点数二分 二分法求平方根的近似值)

收获

  • l<r——>(r-l)>esp,其中esp的精度要大于输出要求的精度

参考代码

#include<iostream>
using namespace std;
int main(){
    double esp = 1e-8,n,l,r,mid;
    cin>>n;
    l = -10000;
    r = 10000;
    while((r-l)>esp){
        mid = (l+r)/2;
        if(mid*mid*mid>=n){
            r=  mid;
        }else l = mid;
    }
    printf("%.6lf",mid);
    return 0;
}

Acwing 799. 最长连续不重复子序列(双指针)

做题情况:完全没有头绪 题解思路

  • i向后遍历,j记录当前连续不重复子系列的起点
  • i每次遍历:
    • 如果有重复元素——j开始向前遍历直至子系列不含重复元素s[a[j++]]--;
    • 用r记录每次遍历可以得到的不重复子系列长度的最大值

参考代码

# include <iostream>
using namespace std;

const int N = 100010;
int a[N], s[N];

int main()
{
    int n, r = 0;
    cin >> n;
    for (int i = 0, j = 0; i < n; ++ i)
    {
        cin >> a[i];
        s[a[i]]++;
        while (s[a[i]] > 1) 
            s[a[j++]]--; 
        r = max(r, i - j + 1) ;
    }
    cout << r;
    return 0;
}

Acwing 801 二进制中1的个数

收获

  • num>>i等价于num÷2的i次方
  • 判断第i位二进制数是否为1:(num>>i)&1

Acwing 846 树的重心

题意:确定树中某个点,使得去掉该点后,该树分成的多个连通块中最大者所含节点最小 参考代码

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int h[N], e[N], ne[N], idx;
int vis[N];
int n,ans = 1e9;
void add(int a,int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int dfs(int u){
    vis[u] = 1;
    int sum = 1, mn = 1;
    for (int i = h[u]; i != -1;i = ne[i]){
        int j = e[i];
        if(!vis[j]){
            int s = dfs(j);
            mn = max(mn,s);
            sum += s;
        }
    }
    mn = max(mn,n-sum);
    ans = min(ans,mn);
    return sum;
}
int main(){
    memset(vis,0,sizeof vis);
    memset(h,-1,sizeof h);
    cin >> n;
    for (int i = 0; i < n-1;i++){
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }
    dfs(1);
    cout << ans << endl;
    return 0;
}

2024ICPC网络预选赛② I. Strange Binary(二进制、位运算)

题意:将数组的二进制数位用-1/1/0表达,其中不能有连续两个0
解题思路

  • 最低两位有两个0,可pass(0或者4的倍数)
  • 对于0001的二进制片段,等效于1 -1 -1 -1

难点

  • 有比较多的边界条件等要考虑,不过只要弄懂数学原理,可以当做是一个模拟题

参考代码

#include <bits/stdc++.h>
#define up(a, b, c) for (int a = b; a <= c; a++)
typedef long long ll;
using namespace std;

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        ll n;
        cin >> n;
        if (n % 4 == 0 || n == 0)
        {
            cout << "NO" << endl;
            continue;
        }
        else
            cout << "YES" << endl;
        vector<int> a;
        for (int i = 0; i < 32; i++)
        {
            a.push_back((n >> i) & 1);
        }
        int i = 0;
        while (i < 31)
        {
            if (a[i] && a[i + 1] == 0)
            {
                a[i] = -1, i++;
                while (i < 31 && a[i] != 1)
                {
                    a[i] = -1, i++;
                }
                if (a[i] == 1)
                    a[i - 1] = 1;
                if (i == 31)
                    a[i] = 1;
            }
            else
                i++;
        }
        // 输出
        for (int i = 0; i < 32; i++)
        {
            if (i % 8 == 0 && i)
                puts("");
            cout << a[i] << " ";
        }
        puts("");
    }
    return 0;
}

巧思

  • ==通过位运算符得出整数的二进制表达式,并且可以控制前缀0的个数(或二进制串的长度)== for(int i = 0;i <=digits;i++) bin[i] = (num>>i)&1;