【贪心】【字典树】Gym - 101466A - Gaby And Addition

题意:定义一种无进位加法运算,给你n个正整数,问你取出两个数,使得他们加起来和最大/最小是多少。

无进位加法运算,其实是一种位运算,跟最大xor那个套路类似,很容易写出对于每个数字,其对应的最优数字是谁,就对于十叉的字典树,贪心地尽量往使结果更优越的方向走即可。

#include<cstdio>
#include<algorithm>
using namespace std;
int ch[1000010*20][10],sz;
typedef long long ll;
ll pw[20];
void Insert(ll x)
{
    int U=0;
    for(int i=18;i>=0;--i){
		if(!ch[U][x/pw[i]%10ll]){
			ch[U][x/pw[i]%10ll]=++sz;
		}
		U=ch[U][x/pw[i]%10ll];
	}
}
ll qmax(ll x){
	int U=0;
	ll res=0;
	for(int i=18;i>=0;--i){
		int wei=x/pw[i]%10ll;
		int k=9;
		for(int j=9-wei;j>=0;--j,--k){
			if(ch[U][j]){
				res+=(ll)k*pw[i];
				wei=j;
				goto OUT;
			}
		}
		for(int j=9;j>9-wei;--j,--k){
			if(ch[U][j]){
				res+=(ll)k*pw[i];
				wei=j;
				goto OUT;
			}
		}
		OUT:
		U=ch[U][wei];
	}
	return res;
}
ll qmin(ll x){
	int U=0;
	ll res=0;
	for(int i=18;i>=0;--i){
		int wei=x/pw[i]%10ll;
		int k=0;
		for(int j=9-wei+1;j<=9;++j,++k){
			if(ch[U][j]){
				res+=(ll)k*pw[i];
				wei=j;
				goto OUT2;
			}
		}
		for(int j=0;j<=9-wei;++j,++k){
			if(ch[U][j]){
				res+=(ll)k*pw[i];
				wei=j;
				goto OUT2;
			}
		}
		OUT2:
		U=ch[U][wei];
	}
	return res;
}
int n;
ll a[1000005];
int main(){
	//freopen("a.in","r",stdin);
	ll ans1=0,ans2=9000000000000000000ll;
	pw[0]=1;
	for(int i=1;i<=18;++i){
		pw[i]=pw[i-1]*10ll;
	}
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%I64d",&a[i]);
		if(i>1){
			ans1=max(ans1,qmax(a[i]));
			ans2=min(ans2,qmin(a[i]));
		}
		Insert(a[i]);
	}
	printf("%I64d %I64d\n",ans2,ans1);
	return 0;
}

原文地址:https://www.cnblogs.com/autsky-jadek/p/8358009.html

时间: 2024-10-14 05:42:24

【贪心】【字典树】Gym - 101466A - Gaby And Addition的相关文章

CodeFoeces GYM 101466A Gaby And Addition (字典树)

gym 101466A Gaby And Addition 题目分析 题意: 给出n个数,找任意两个数 “相加”,求这个结果的最大值和最小值,注意此处的加法为不进位加法. 思路: 由于给出的数最多有 1e6 个,且每个数的值最大为 1e18 ,又因为特殊的加法运算,我们自然无法用常规的方法解决 注意到这个加法运算可以分配到每一位上进行运算,而且最大为1e18,十九位数,那么我们就可以用字典树来存储每个数,并进行计算,为了将字典树每个结点的深度和数的位数对应起来,我们可以将每个数都处理为19位数,

Ancient Printer HDU - 3460 贪心+字典树

The contest is beginning! While preparing the contest, iSea wanted to print the teams' names separately on a single paper. Unfortunately, what iSea could find was only an ancient printer: so ancient that you can't believe it, it only had three kinds

A .Gaby And Addition (Gym - 101466A + 字典树)

题目链接:http://codeforces.com/gym/101466/problem/A 题目: 题意: 给你n个数,重定义两个数之间的加法不进位,求这些数中两个数相加的最大值和最小值. 思路: 字典树.我们首先将前i-1为放入字典树中,然后在查询第i位时,我们去字典树中查询,对每一位进行寻找,找到满足题意的当前位的最大值和最小值,然后继续更新下一位,最后维护总的最大值和最小值即可. 代码实现如下: 1 #include <set> 2 #include <map> 3 #i

HDU 4825 Xor Sum(经典01字典树+贪心)

Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total Submission(s): 1555    Accepted Submission(s): 657 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Ze

01字典树贪心查询+建立+删除(个人模版)

01字典树贪心查询+建立+删除: 1 #define maxn 2 2 typedef struct tree 3 { 4 tree *nex[maxn]; 5 int v; 6 int val; 7 }tree; 8 tree root; 9 void init() 10 { 11 for(int i=0;i<maxn;i++) 12 { 13 root.nex[i]=NULL; 14 } 15 } 16 void creat(char *str,int va) 17 { 18 int len

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

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

ACM: Gym 100935F A Poet Computer - 字典树

Gym 100935F A Poet Computer Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description standard input/output The ACM team is working on an AI project called (Eih Eye Three) that allows computers to write poems. One of th

HDU 5536 Chip Factory 字典树+贪心

给你n个数,a1....an,求(ai+aj)^ak最大的值,i不等于j不等于k 思路:先建字典树,暴力i,j每次删除他们,然后贪心找k,再恢复i,j,每次和答案取较大的,就是答案,有关异或的貌似很多都用字典树,也是醉了 /*Problem : 5536 ( Chip Factory ) Judge Status : Accepted RunId : 15506230 Language : G++ Author : qianbi08*/ #include<iostream> #include&

NEUOJ711 异星工厂 字典树+贪心

题意:你可以收集两个不相交区间的权值,区间权值是区间异或,问这两个权值和最大是多少 分析:很多有关异或求最大的题都是利用01字典树进行贪心,做这个题的时候我都忘了...最后是看别人代码的时候才想起来这个套路 l[i],记录,从 1 到 i  里 最大的异或区间权值, r[i], 记录,从  i 到 n 里 最大的异或区间权值 这样两轮插入,然后查询贪心就行了,插入的是前缀和后缀的异或2进制序列,从大的开始(贪心) 注:吐槽,其实都是套路,异或和求最大,往往要利用字典树进行贪心 #include