紫书第三章例题--UVa1583

题目:UVa1583

 

地址:https://vjudge.net/problem/UVA-1583

 

题解:

如果x加上x的各个位上的数字后得到y,就说x是y的生成元。给出n(1<=n<=100000),求最小生成元(若没有生成元,就输出0)。例如,n=216,输出198,n=121,输出0。

 

思路:

对于一个n,不难发现它的生成元肯定是小于n,那么知道它的生成元的范围后,可以直接暴力枚举呀。

不过问题来了,一个n,你可以直接枚举,但是如果有很多组n呢,而且n最大可以为100000,只要1000个这个最大量级的输入,就有可能会超时。

可以想到制表,可以把100000以内的数事先算出来,制成表(table[i]=sum表示i是sum的生成元),然后要输出时,依次枚举1~n的table值,找出第一个table值等于n的i(即最小生成元),但是你会发现,依旧会超时,尽管节省了算生成元的时间,但是每次输出的时间复杂度依旧是O(n),那么可不可以优化输出时的复杂度呢,答案是肯定的。

只要在制表的时候将值和下标颠倒一下就可以了,即table[sum]=i,这样sum的生成元就是table[sum],可以直接输出,复杂度降到了O(1)!!!

 

 

编程技巧:

① 对于会重复用到的且可以事前计算的,可以在输入之前,提前制表。

 

注意点:

①  由于题目要求的是最小生成元,所以在制表时,就得注意要把最小的生成元放进table数组中。if(!table[sum]||sum<table[sum])      table[sum] = i;

 

 

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<cstring>
#include<vector>
using namespace std;

int T;
int table[100005];

void Init(){                ///预处理,制表
    memset(table,0,sizeof(table));              ///初始化为0,这样就保证了没有生成元的数将输出0
    for(int i = 0;i <= 100005;++i){
        int x = i;
        int sum = 0;
        while(x){
            sum += x%10;
            x /= 10;
        }
        sum += i;           ///i是sum的生成元
        if(!table[sum]||sum<table[sum])     ///其中sum<table[sum]一句是为了保证table[sum]中放的是sum最小的生成元
            table[sum] = i;
    }
}

int main(){
    Init();
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        cout << table[n] << endl;           ///直接输出答案
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值