Happy Number

传送门…

题目大意:

如果一个正整数仅含有数字2、3、6,则它是“快乐正整数”
如:2,3,6,22,23,26,236…是,25、235…则不是。
输入n (1 ≤ n ≤ 10^9), 输出第n个快乐正整数 num。

基本思路:

大意:

1.确定 num 是几位数:
每位都2,3,6三种可能,故 n 位数就有 [3 ^ n] 个“快乐正整数”,用数组a[ ]存。
用数组b[ ]存前 n 位数共 b[ i ] 个“快乐正整数”,如果 b[ i - 1 ] ≤ n ≤ b[ i ] 则 num 是位数为 i 的十进制数。
记 num 是 p 位数。
2.确定每一位是数字2,3或6:
a[p]三等分,一等输出 “2”,m不做处理 ;二等输出 “3” ,m减去a[p] / 3 ;三等输出 “6”,m减去 a[p] / 3 * 2。
循环,p 自减, p = 0 时 结束循环。
ps:发现规律是这样,暂给不出合理的解释或定理解析

详解:

一位数:2,3,6。共(3 ^ 1 = 3)个
两位数:22,23,26,32,33,36,62,63,66。共(3 ^ 2 = 9)个
……
n 位数:共(3 ^ n )个
理解:每位都2,3,6三种可能,故n位数就有 [3 ^ n] 个“快乐正整数”
|
前一位数:共 [3] 个
前两位数:共 [3 + 9 = 12] 个
……
前 n 位数:共 [3 ^ 1 + 3 ^ 2 + … + 3 ^ n] 个
前缀和数组b[ ]可存,如果 b[i - 1] ≤ n ≤ b[i] 则 num 是位数为 i 的十进制数。
|
于是我们确定了第 n 个“快乐数”(即 num )的位数为 p 。
m = n - b[p - 1] , p 位数的第 m 个即是第 n 个“快乐数”。

|
紧接着,需要确定每一位上是2 or 3 或 6…
对数组 a[p] 进行三等分:
如果 m 在第 1 等,即 m ≤ a[p] / 3,则这一位的数是“2”;
如果 m 在第 2 等,即 a[p] / 3 ≤ m ≤ 2 * a[p] / 3,则这一位的数是“3”;
如果 m 在第 3 等,即 2 * a[p] / 3 ≤ m ≤ a[p] ,则这一位的数是“6”;
每一次循环 p 进行自减操作, p = 0 时 结束循环。

举例:

数组a[ ]代表第 i 位有 a[ i ] 个“快乐数”,数组b[ ]代表前 i 位有 b[ i ] 个“快乐数”

eg: cin >> 680 ;
a[1] = 3,a[2] = 9 , a[3] = 27,a[4] = 81 , a[5] = 243,a[6] = 729
b[1] = 3,b[2] = 12,b[3] = 39,b[4] = 120,b[5] = 363,b[6] =1092

n = 680,大于b[5] 且 小于b[6],故 num 为六位数,即 p = 6 。
m = n - b[5] = 417,六位数的第 m 个即是第 n 个“快乐数”。

per = a[p] / 3, 用于从 高位 往 低位 依次确定每一位是几。
注:第几位是从右往左数,每一步循环都进行p自减操作,即第 p 位
当 p = 0 时结束循环,刚好输出一个六位数。

第 6 位:per = 243, per ≤ m ≤ 2 * per。
故第 6 位是 “3”,m = m - per = 74。
第 5 位:per = 81, m ≤ per。
故第 5 位是 “2”,m不做处理。
第 4 位:per = 27, 2 * per ≤ m ≤ 3 * per。
故第 4 位是 “6”,m = m - 2 * per = 20。
第 3 位:per = 9, 2 * per ≤ m ≤ 3 * per。
故第 3 位是 “6”,m = m - 2 * per = 2。
第 2 位:per = 3, m ≤ per。
故第 2 位是 “2”,m不做处理。
第 1 位:per = 1, per ≤ m ≤ 2 * per。
故第 1 位是 “3”,m = m - 2 * per = 0,此时 p 也为零,结束。
所以结果 num = 326623 。

代码样例:

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main()
{
    int n; scanf("%d",&n);
    int res = 1, p;
    for(int i=1; b[i-1] < n; i++) {// 循环结束标准为 b[i-1] < n
        res *= 3;
        a[i] = res;
        b[i] = b[i-1] + a[i];
        p  = i;// 不断更新p,确定num是p位数
    }
    int m = n-b[p-1]; // p 位数的第 m 个即是第 n 个“快乐数”
    while(p) {
        int per = a[p]/3;// 三等分 a[p]
        p--;
        if(m <= per) {
            cout << "2";
        } else if(m <= per*2) {
            m -= per;
            cout << "3";
        } else {
            m -= per*2;
            cout << "6";
        }
    }
    return 0;
}

总结:

一开始我压根都没考虑时间复杂度,一直在想着跑循环,然后做一些特判、打表之类的,然而n实在太大了,毫不意外TLE掉。
后来跟队友确定这题是用巧妙构造过的,然后我就一直在那里看样例、抠规律,最后成功签到。
打多校联赛基本上都是签到了就走,要么就是一直罚坐陪跑。这一题封榜前有1300人左右pass,不是高难度的题,但也是自己“辛辛苦苦”好久后才做出来,喜悦自然有,更多的还是get到什么才是 算法 吧。en,继续努力。

(Telephone Number Word Generator) Standard telephone keypads contain the digits 0 through 9. The numbers 2 through 9 each have three letters associated with them, as is indicated by the following table: Many people find it difficult to memorize phone numbers, so they use the correspondence between digits and letters to develop seven-letter words that correspond to their phone numbers. For example, a person whose telephone number is 686-2377 might use the correspondence indi- cated in the above table to develop the seven-letter word “NUMBERS.” Businesses frequently attempt to get telephone numbers that are easy for their clients to remember. If a business can advertise a simple word for its customers to dial, then no doubt the business will receive a few more calls. Each seven-letter word corresponds to exactly one seven-digit telephone number. The restaurant wishing to increase its take-home business could surely do so with the number 825-3688 (i.e., “TAKEOUT”). Each seven-digit phone number corresponds to many separate seven-letter words. Unfortunately, most of these represent unrecognizable juxtaposi- tions of letters. It’s possible, however, that the owner of a barber shop would be pleased to know that the shop’s telephone number, 424-7288, corresponds to “HAIRCUT.” A veterinarian with the phone number 738-2273 would be happy to know that the number corresponds to “PETCARE.” Write a program that, given a seven-digit number, writes to a file every possible seven-letter word corresponding to that number. There are 2187 (3 to the seventh power) such words. Avoid phone numbers with the digits 0 and 1.
最新发布
06-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值