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++]]--;
- 如果有重复元素——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;