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

gym 101466A Gaby And Addition

题目分析

题意:

给出n个数,找任意两个数 “相加”,求这个结果的最大值和最小值,注意此处的加法为不进位加法。

思路:

由于给出的数最多有 1e6 个,且每个数的值最大为 1e18 ,又因为特殊的加法运算,我们自然无法用常规的方法解决

注意到这个加法运算可以分配到每一位上进行运算,而且最大为1e18,十九位数,那么我们就可以用字典树来存储每个数,并进行计算,为了将字典树每个结点的深度和数的位数对应起来,我们可以将每个数都处理为19位数,从高位依次存入字典树,这样一来,就方便我们求最值了。

然后就是求最值的问题,我最初的想法是先将所有数存入字典树,随后枚举字典树的每条链(从根结点到叶子节点的路径),以求出最值,不过TLE了,想来这样写确实时间比较长,最坏的情况下查询用时:5 ^ 18 次,大约3.8e13次运算, 妥妥地TLE。不过我们可以在插入某个数之前,求出这个数和字典树中存在的数“相加”的得到的最值,随后将这个数存入字典树,最后所有数存入字典树后,就可以得到最值了。

总结:

这个题目写了我近半天,确定是字典树后,由于求最值这里对原方法用时估计错误,导致自己一直TLE在第四组样例,后来请教同学才发现问题。

还有就是这个地方求最值的时候不要用递归,在这里递归的效率很低。

代码区

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
unsigned const long long inf = (ull)10000000000000000000;
const int mod = 1e9 + 7;
const int Max = 2e7 + 10;

struct Node
{
    int maps[10];
}node[Max];

int n,id;
ull num[22];
ull max_val, min_val;
char str[45], str2[45];
char lead[][19]{ "","0","00","000","0000","00000" ,"000000","0000000","00000000","000000000",
    "0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000",
    "00000000000000000","000000000000000000"};    //用于补充前导零,使得数凑成19位数

void insert()                                    //字典树常规插入操作
{
    int root = 0;
    for (int i = 0;i < 19;i++)
    {
        if (node[root].maps[str[i] - ‘0‘] == 0) node[root].maps[str[i] - ‘0‘] = ++id;
        root = node[root].maps[str[i] - ‘0‘];
    }
}

ull dfs(int mode)                                //mode == 1代表求最大值
{
    ull val = 0;
    int root = 0;
    for (int i = 0; i <= 18;i++)                //最大19位数
    {
        int id = -1;
        ull t = 0;                                //记录这个位置上的最大(小)值
        if (mode == 0) t = 9;

        for (int j = 0;j <= 9;j++)
        {
            if (mode && node[root].maps[j] && (j + str[i] - ‘0‘) % 10 >= t)
            {
                id = j;t = (j + str[i] - ‘0‘) % 10;
            }
            else if (!mode && node[root].maps[j] && (j + str[i] - ‘0‘) % 10 <= t)
            {
                id = j;t = (j + str[i] - ‘0‘) % 10;
            }
        }
        val += num[i] * t;
        root = node[root].maps[id];
    }
    return val;
}

int main()
{
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    num[18] = 1;
    for (int i = 17;i >= 0;i--)
    {
        num[i] = num[i + 1] * 10;    //预处理出1 ~ 1e18
    }

    id = 0;                            //控制字典树结点数s
    min_val = inf;
    max_val = 0;

    scanf("%d", &n);
    for (int i = 1;i <= n;i++)
    {
        scanf("%s", str2);
        int len = strlen(str2);
        strcpy(str, lead[19 - len]);
        strcat(str, str2);            //将数补充为19位数

        if (i != 1)                    //找最值的前提:至少有两个以上的数
        {
            max_val = max(max_val, dfs(1));
            min_val = min(min_val, dfs(0));
        }
        insert();
    }
    if (min_val == inf) min_val = 0;
    printf("%llu %llu\n", min_val, max_val);
    return 0;
}

/*
附上一组样例,如果 wrong on test 3 的话,可以用一下,这个是数极限大的情况
input
7
1000000000000000000
1000000000000000000
999999999999999999
1000000000000000000
1000000000000000000
1000000000000000000
1234567890987654321

output
1123456789876543210 2234567890987654321
 */

gym 101466A Gaby And Addition (字典树)

原文地址:https://www.cnblogs.com/winter-bamboo/p/11343262.html

时间: 2024-10-09 20:00:26

CodeFoeces GYM 101466A Gaby And Addition (字典树)的相关文章

【贪心】【字典树】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 p

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

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

codeforces gym #101161F-Dictionary Game(字典树+树上删边游戏)

题目链接: http://codeforces.com/gym/101161/attachments 题意: 给一个可以变化的字典树 在字典树上删边 如果某条边和根节点不连通那么这条边也删除 谁没得删就输了 数据范围: $1\leq n \leq 100000$ $1\leq q \leq 100000$ $1\leq |s| \leq 40$ 分析: ac代码: #include<bits/stdc++.h> using namespace std; #define ll long long

hdu 1251 统计难题(字典树)

Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串. 注意:本题只有一组测试数据,处理到文件结束. Output 对于每个提

51nod round3# 序列分解(折半枚举+字典树)

小刀和大刀是双胞胎兄弟.今天他们玩一个有意思的游戏. 大刀给小刀准备了一个长度为n的整数序列.小刀试着把这个序列分解成两个长度为n/2的子序列. 这两个子序列必须满足以下两个条件: 1.他们不能相互重叠. 2.他们要完全一样. 如果小刀可以分解成功,大刀会给小刀一些糖果. 然而这个问题对于小刀来说太难了.他想请你来帮忙. Input 第一行给出一个T,表示T组数据.(1<=T<=5) 接下来每一组数据,输入共2行. 第一行包含一个整数n (2<=n<=40且为偶数). 第二行给出n

白话算法与数据结构之【字典树】

1. 什么是trie树 1.Trie树 (特例结构树) Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高.      Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子

[算法系列之二十]字典树(Trie)

一 概述 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计. 二 优点 利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高. 三 性质 (1)根节点不包含字符,除根节点外每一个节点都只包含一个字符: (2)从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串: (3)每个节点的所有子节点包含的字符都不相同. 单词列表为"apps&

poj 3764 The xor-longest Path(字典树)

题目链接:poj 3764 The xor-longest Path 题目大意:给定一棵树,每条边上有一个权值,找出一条路径,使得路径上权值的亦或和最大. 解题思路:dfs一遍,预处理出每个节点到根节点路径的亦或和rec,那么任意路径均可以表示rec[a] ^ rec[b],所以问题 就转换成在一些数中选出两个数亦或和最大,那么就建立字典树查询即可. #include <cstdio> #include <cstring> #include <algorithm> us