The 2022 ICPC Asia Regionals Online Contest (I)-D题题解(DFS暴搜+剪枝+打表去重+二分)

简介: 时间复杂度:O(227 + nlog(n) + T * log(n)),227是DFS打表的时间,nlog(n)是vertor排序的时间,T*log(n)是询问次数和二分搜答案的时间。(如果算错了,评论或者私信指出谢谢)

这次比赛很好,题也很好,就是下午人不太清醒,没做出来太菜了,回去才写出来的。

比赛原题已经上架到PTA了:点击跳转


题目


105875edd66443eaaaef4dbe4cc1379f.png


解释


题目意思其实很简单,就是给你一个[l, r]的区间你去找一个数,满足他后缀连续的0的个数等于前面的1的个数,举个例子68:二进制形式1000100,后缀连续的零的个数ctz(68)=2,前面1的个数popcount(68)=2,刚好相等所以他就是一个good的数。


思路


方法:DFS暴搜+剪枝+打表去重+二分


题目的意思不就是让你怎么去排列后缀零前面的1的位置和个数,直接用dfs暴搜出所有的good数,因为x只有1e9的范围,二进制也就是30位,我们从高往低去搜,当前位选1或者0,用两层for循环,外面那层我们用来枚举位数,里面枚举后缀0的个数。


dfs传递的是我们枚举的后缀0的个数now(需要多个1),当前到dfs哪一位step以及用了几个1(one)。


剪枝:我们当前位超过了后缀0的个数就return。


我们搜出now == one的时候就是good的数,用unordered_map和vector用来去重和保存。


dfs搜完后,把vector的数sort一下,后面求区间内的数用lowwer_bound(l)找就行。


代码


#include<bits/stdc++.h>
#define CL(a,b)  memset(a,b,sizeof(a))
using namespace std;
const int maxn = 1e5+10;
const int mod  = 1e9+7;
int T, l, r;
vector<int>num;
unordered_map<int,int>nums;
int tot;
void dfs(int now,int step,int need) {
  if(now==need) {
    if(!nums[tot])num.push_back(tot);
    nums[tot]=1;
    return;
  }
  if(step==now)return;
  for(int i=1; i>=0; i--) {
    if(i)need++, tot += 1 << step;
    step--;
    dfs(now,step,need);
    step++;
    if(i)need--, tot -= 1 << step;
  }
  return;
}
void solve() {
  for(int len = 30 ; len >= 2; len--) //构造的数的长度
    for(int p = 1; p <= len / 2 ; p++) { //构造末尾0
      tot = 1 << p;
      dfs(p,len-1,1);
    }
}
int getnum(int l) {
  return lower_bound(num.begin(),num.end(),l)-num.begin();
}
int main() {
  solve();
  sort(num.begin(),num.end());
  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d",&l,&r);
        int ans = num[getnum(l)];
        if(ans <= r)printf("%d\n", ans);
        else printf("-1\n");
    }
  return 0;
}

e829f6ec8b0d4bdd8189287612f744bb.png


复杂度分析


  • 时间复杂度:O(227 + nlog(n) + T * log(n)),227是DFS打表的时间,nlog(n)是vertor排序的时间,T*log(n)是询问次数和二分搜答案的时间。(如果算错了,评论或者私信指出谢谢)


  • 空间复杂度:O(n),n表示good的数的数量,我搜出来差不多有这么多


e5e2fd56c921473788b9d139b16e2661.png

目录
相关文章
|
5月前
【洛谷 P1219】[USACO1.5]八皇后 Checker Challenge 题解(深度优先搜索+回溯法)
**USACO1.5八皇后挑战**是关于在$n\times n$棋盘上放置棋子的,确保每行、每列及两条主对角线上各有一个且仅有一个棋子。给定$6$作为输入,输出前$3$个解及解的总数。例如,对于$6\times6$棋盘,正确输出应包括解的序列和总数。代码使用DFS解决,通过跟踪对角线占用状态避免冲突。当找到所有解时,显示前三个并计数。样例输入$6$产生输出为解的前三个排列和总数$4$。
35 0
|
6月前
|
算法 测试技术
每日一题:LeetCode-LCR 007. 三数之和
每日一题:LeetCode-LCR 007. 三数之和
华为机试HJ44:Sudoku(数独问题,深度优先遍历DFS解法)
华为机试HJ44:Sudoku(数独问题,深度优先遍历DFS解法)
128 0
|
6月前
CF1132D Streessful Training(二分+贪心+优先队列*2300)
CF1132D Streessful Training(二分+贪心+优先队列*2300)
32 0
|
11月前
|
算法 测试技术
每日一题:LeetCode-LCR 143.子结构判断
每日一题:LeetCode-LCR 143.子结构判断
|
人工智能
poj 2299 Ultra-QuickSort 求逆序数 树状数组解法
所谓离散化,我们的了解就是对原数组排序,然后用所在位置的下标代替原数,这样我们就可以把数据范围缩小到1-500000,这个数组是开的下的。
42 0
|
开发框架 .NET
poj 3468 A Simple Problem with Integers线段树区间修改
题目意思很简单,有N个数,Q个操作, Q l r 表示查询从l到r 的和,C l r v 表示将从l到r 的值加上v,明显的线段树,不知道线段树的人肯定暴力,肯定超时,哈哈!!
30 0
|
人工智能
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
|
机器学习/深度学习 Java
【每日一题Day64】LC1799N 次操作后的最大分数和 | 状态压缩dp 状态压缩+dfs+记忆化搜索
每个数字有两种状态,删除或者未删除,因此可以使用状态压缩记录未删除的数字情况state,便于使用位运算进行状态的遍历及转移;使用状态压缩dp找到将所以数字删除的最大分数
101 0
【每日一题Day64】LC1799N 次操作后的最大分数和 | 状态压缩dp 状态压缩+dfs+记忆化搜索
AtCoder Beginner Contest 216 G - 01Sequence (并查集 贪心 树状数组 差分约束)
AtCoder Beginner Contest 216 G - 01Sequence (并查集 贪心 树状数组 差分约束)
151 0