Codeforces 1285D Dr. Evil Underscores(字典树,dp)

传送门

题意:

有一个长度为 \(n\ (1\leq n\leq 10^5)\)的整数序列 \(a_1,\cdots,a_n\ \ (0\leq a_i\leq 2^{30}-1)\),你需要找到一个非负整数 \(X\) 使得 \(\max(a_i\oplus X)\)最小,其中 \(\oplus\) 为按位异或运算。

输入这个序列,输出\(\max(a_i\oplus X)\)的最小值。

思路:

1.数组中的每个数的二进制下的某位(第k位)都是0或者是1,那么x的第k位取值是0或者1,使得答案中的第k位一定是0(这样得到的结果才会更小)。
2.数组中的每个数的二进制下的某位(第k位)有1又有0,不管x的第k位取得0或1,异或后的结果都是1(因为我们找的是\(\max(a_i\oplus X)\),只要有1肯定要算)。所得答案的第k位一定是1,然后取最小的值对于剩下的k-1位(递归就行)。

代码:

//借鉴了qscqesze大佬的代码,写的很漂亮,我加上了注释
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int MAXN=2e5+50;
const double pi=3.1415926536;
int t,n;
vector<int> a;
int solve(vector<int> p,int k){
    if(p.size()==0||k<0)return 0;
    vector<int> p1,p2;
    for(int i=0;i<p.size();i++){
        if((p[i]>>k)&1)p1.push_back(p[i]);//第k位是1的放p1里
        else p2.push_back(p[i]);//第k位是0的放p2里
    }
    if(p1.size()==0)return solve(p2,k-1);//p1里面没元素,说明所有的第k位都是0,答案的第k位为0,只用考虑p2的后面k-1位即可
    if(p2.size()==0)return solve(p1,k-1);//p2里面没元素,说明所有的第k位都是1,答案的第k位为0,只用考虑p1的后面k-1位即可
    return (1<<k)+min(solve(p1,k-1),solve(p2,k-1));//答案的第k位为1,值为(1<<k),考虑后面k-1位里,p1,p2能够取得的最小值,贪心
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        a.push_back(x);
    }
    printf("%d\n",solve(a,30));
    return 0;
}

Summary

解决的代码类似贪心,但好多大佬说这是字典树模版题,这个代码也用到了字典树的思想,只是不用建树,直接解决的。这个还用用dp写的,意思是树上dp,其实思路差不多,dp的话就是不用递归直接在数组里算出来输出就行.

原文地址:https://www.cnblogs.com/zzl-dreamfly/p/12228827.html

时间: 2024-10-31 23:45:32

Codeforces 1285D Dr. Evil Underscores(字典树,dp)的相关文章

CodeForces 1285D Dr. Evil Underscores

Description CodeForces 1285D 描述 给一个长度为 $n$ 的数组 $a$,试找到一个 $X$,使得 $\max\limits_{1\le i \le n} (a_i \oplus X)$ 最小,输出这个最小值即可. 输入 第一行一个数 $n(1 \le n \le 10^5)$,接下来第二行 $n$ 个数表示 $a$ 数组 $(0\le a_i \le 2^{30} - 1)$. 输出 一行一个数,表示所求最小值. 样例 输入1 31 2 3 输出1 2 输入2 21

CodeForces 706D Vasiliy&#39;s Multiset (字典树查询+贪心)

题意:最开始的时候有一个集合,集合里面只有一个元素0,现在有q次操作,操作分为3种: + x: 表示向集合中添加一个元素x - x:表示删除集合中值为x的一个元素 ? x:表示查询集合中与x异或的最大值为多少 析:这是一个字典树的应用,不过确实没看出来....主要思想是这样,先用10进制数,转成二进制数,记下每个结点的0,1的个数,这样增加和删除,就是对01的删除, 剩下的就是查询,那么尽量让0和1XOR是最大的,所以,对于给定数,我们要去尽量他的XOR数,如果找到就加上,找不到,就找下一个.这

Dr. Evil Underscores

D - Dr. Evil Underscores 参考:Codeforces Round #613 (Div. 2) Editorial 其实比赛的时候就已经想到了基本上一样的解法,可是最后还是没有写出来... 具体思路就是分治,在二进制中,如果\(a_1{\sim}a_n\),在该位上既有1又有0,说明这一位上的数是躲不掉的,那么这一位上肯定是1,所以在返回的数里加一个1<<i,而对于后面的数则取最小值即可min(dfs(i-1, v0), dfs(i-1, v1))+(1 <<

2010辽宁省赛 NBUT 1222 English Game【字典树+DP】

[1222] English Game 时间限制: 1000 ms 内存限制: 131072 K 链接:Click Here! 问题描述 This English game is a simple English words connection game. The rules are as follows: there are N English words in a dictionary, and every word has its own weight v. There is a wei

UVALive 3942 Remember the Word 字典树+dp

/** 题目:UVALive 3942 Remember the Word 链接:https://vjudge.net/problem/UVALive-3942 题意:给定一个字符串(长度最多3e5)和m个单词(每个单词长度最多100).单词都是不同的.该字符串可以由若干个单词组成,问最多有多少种组合方式. 思路:字典树+dp 用字典树处理好m个单词,定义dp[i]表示从i开始的字符串可以由单词组成的方式数. 那么dp[i] += dp[i+j]; j表示某个单词和字符串的[i,i+j-1]匹配

Codeforces 219D. Choosing Capital for Treeland (树dp)

题目链接:http://codeforces.com/contest/219/problem/D 树dp 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio&

zoj3013Word Segmenting (字典树+dp)

Word Segmenting Time Limit: 5 Seconds Memory Limit: 32768 KB Special Judge One key technology in Chinese search engine is Word Segmenting, which is more difficult than English Word Segmenting, as there is no space between words. A traditional solutio

codeforces 456d (字典树+DP)

题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 思路:00 代表不能控制 01代表败,10代表胜,11代表能输能赢 转自  http://blog.csdn.net/blankcqk/article/details/38459033 附带字典树模版: void insert(){ int len = strlen(s); int no

HDU5715 XOR 游戏 二分+字典树+dp

当时Astar复赛的时候只做出1题,赛后补题(很长时间后才补,懒真是要命),发现这是第二简单的 分析: 这个题,可以每次二分区间的最小异或和 进行check的时候用dp进行判断,dp[i][j]代表前i个元素分成j个区间,j是最后一个区间的最后一个元素 如果dp[i][j]为真,表明每个区间长度大于L,异或和大于mid 否则为假 返回dp[n][m]就好 复杂度度 O(30^2*nm) 吐槽:和异或相关的题总是和字典树贪心有关,又是一道,铭记铭记 #include <stdio.h> #inc