2019年清华软院推免考试(校外直博&校内硕/博) 第三题——同构数

问题描述

2018年清华软院推免考试(校外直博&校内硕/博)

第三题——同构数

 

如果一个数n满足:记n的位数为d(n),若n的各次幂的末d(n)位都与n相等,则称n为“同构数”。现在题目是,输入进制m和正整数k,求m进制下第k个同构数,例如10进制下第4个同构数是25(1,5,6,25)。这里约定所有进制的第一个同构数都是1.

规模约定:m大于5小于16,k小于21,保证结果存在且小于INT_MAX,但不保证中间计算过程不会超出INT_MAX

示例:

Input

6 2

Output

3

(因为是考后回忆,可能记忆有些模糊了,题干和代码都有可能有错,忘谅解)

------------------------------------------------------------

思路

笔者想到的方法是高精度+动态规划(类似的一个思路)。

注意到同构数的两个性质:

1. 如果一个数和它的平方结尾相等,则这个数和它的各次幂的结尾都相等,因此仅凭平方就能判定这个数是同构数

2. 一个n位同构数的末(n-1), (n-2), …,2, 1位也是同构数,这个性质决定了可以采用类似动态规划的方法大大减少计算量

所谓“类似动态规划的方法”是:

首先计算1位的同构数,保存在vector中;

2位的同构数的个位一定在vector中,因此只要枚举个位是vector中的数的十位数进行判断,将2位的同构数添加到vector中;

3位的同构数要么后两位是2位的同构数,要么第2位是0,个位是1位的同构数,再对符合条件的3位数枚举判断添加;

以此类推……

其实这道题打表完全是可以的,但由于清华软院机试不是OJ,怕老师会看代码,因此没敢打表。

另外就是本题可以在第一题的代码上修改,需要增加的代码量并不大。

------------------------------------------------------------

代码

#define _CRT_SECURE_NO_WARNINGS

//输入两个长度不超过200的正整数A,B,求A和B的乘积。保证输入的正整数不会以0开头,要求输出的正整数也不能以0开头

#include <cstdio>
#include <cstring>
#include<vector>
using namespace std;


class BigInteger {
public:
    static const int maxn = 1010;
	static int BASE;

	BigInteger (void)
	{
		n = 1;
		memset(digit, 0, sizeof(digit));
	}

	BigInteger (int one_digit)
	{
		n = 1;
		memset(digit, 0, sizeof(digit));
		digit[0] = one_digit;
	}

    BigInteger &operator=(const BigInteger &rhs) {
        n = rhs.n;
        for (int i = 0; i < n; i++) {
            digit[i] = rhs.digit[i];
        }
        return *this;
    }

    int digit[maxn], n;

    void readInput() {
        static char buffer[maxn];
        scanf("%s", buffer);
		int len = strlen(buffer);
		n = 0;
        for (int i = len - 1; i >= 0; i--) {
            digit[n++] = buffer[i] - '0';
        }
    }

    void normalize(int i) {
        n = i;
        while (n > 1 && digit[n - 1] == 0) {
            n--;
        }
    }

    void clear0() {
        n = 1;
        memset(digit, 0, sizeof(digit));
    }

	void add(const BigInteger &rhs, BigInteger &result) const{
		int i, si = 0;
		result.clear0();
		for (i = 0; i < n + rhs.n; i++)
		{
			result.digit[i] = si + digit[i] + rhs.digit[i];
			result.digit[i+1] = result.digit[i] / BASE;
			result.digit[i] = result.digit[i] % BASE;
		}
		result.normalize(n+rhs.n);
	}

    void sub(const BigInteger &rhs, BigInteger &result) const {//ensure *this >= rhs
        int i, x = 0;
        for (i = 0; i < n; i++) {
            x += digit[i];
            if (i < rhs.n) {
                x -= rhs.digit[i];
            }
            bool borrow = false;
            if (x < 0) {
                x += BASE;
                borrow = true;
            }
            result.digit[i] = x;
            if (borrow) {
                x = -1;
            } else {
                x = 0;
            }
        }
        result.normalize(i);
    }

    void mul(const BigInteger &rhs, BigInteger &result) const {
        for (int i = 0; i < n + rhs.n; i++) {
            result.digit[i] = 0;
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < rhs.n; j++) {
                result.digit[i + j] += digit[i] * rhs.digit[j];
                if (result.digit[i + j] >= BASE) {
                    result.digit[i + j + 1] += result.digit[i + j] / BASE;
                    result.digit[i + j] %= BASE;
                }
            }
        }
        result.normalize(n + rhs.n);
    }

	void left_shift(int L)
	{
		int i;
		for (i=n-1; i>=0; i--)
		{
			digit[i+L] = digit[i];
		}
		for (i=L-1; i>=0; i--)
		{
			digit[i] = 0;
		}
		n += L;
	}

	bool tail (const BigInteger &rhs) const {	// ensure rhs >= *this
		for (int i = 0; i < n; i++)
		{
			if (digit[i] != rhs.digit[i])
			{
				return false;
			}
		}
		return true;
	}

    int compare(const BigInteger &rhs) const {
        if (n != rhs.n) {
            return n - rhs.n;
        }
        for (int i = n - 1; i >= 0; i--) {
            if (digit[i] != rhs.digit[i]) {
                return digit[i] - rhs.digit[i];
            }
        }
        return 0;
    }

    void output() const {
        bool started = false;
        for (int i = n - 1; i >= 0; i--) {
                putchar('0' + digit[i]);
            }
		putchar('\n');
	}

	int toBASE10()					// switch to integer of BASE 10
	{
		int ret = 0, i, multiplier = 1;
		for (i=0; i<n; i++)
		{
			ret += digit[i] * multiplier;
			multiplier *= 10;
		}
		return ret;
	}

 
};

int BigInteger::BASE;

int main() {
	int m = 10, k = 4, cnt = 0, i = 0, j = 1;
	scanf("%d%d", &m, &k);
	BigInteger::BASE = m;
	BigInteger A, B, C;
	vector<BigInteger> v;
	do {
		if (i == 0)
		{
			for (j=1; j<m; j++)
			{
				A = BigInteger(j);
				A.mul(A, C);
				if (A.tail(C))
				{
					cnt++;
					v.push_back(A);
				}
				if (cnt == k)
				{
					goto mark;
				}
			}
			i++;
		}
		else
		{
			vector<BigInteger> pre(v);
			for (j = 1; j<m; j++)
			{
				B = BigInteger(j);
				B.left_shift(i);
				for (vector<BigInteger>::iterator it = pre.begin(); it != pre.end(); it++)
				{
					B.add(*it, A);
					A.mul(A, C);
					if (A.tail(C))
					{
						cnt++;
						v.push_back(A);
					}
					if (cnt == k)
					{
						goto mark;
					}
				}
			}
			i++;
		}
	}while (cnt < k);
	mark: printf("%d", A.toBASE10());
    
    return 0;
}

 

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/82718296