似乎没有什么技术含量,没有按照佳哥的写,直接用了log10的方法求位数,时间开销是1.5,如果按位数处理肯定更快,但是代码就要复杂很多。但是应用floyd判圈算法更快。

Floyd判圈算法

可以抽象成为两个小孩跑步,但是一个小孩的速度是另一个小孩的两倍,当跑的快的小孩追上跑的慢的小孩的时候,算法结束。此外,时间复杂度为 $O(1)$ 也是格外炫酷。

一个next一次,另一个next两次,很快便可以追上。

可能提出疑问:

既然肯定又重复的地方,为啥不让第一个小孩就在那里等呢?因为算法运行结果不一定是在小孩等的地方结束,可能还没有跑进圈里!

复杂AC

c#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;

#define lln long long 
lln n, k;

int main()
{
    int T;
    lln mm, temp;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%lld", &n, &k);
        mm = k;
        set <lln> s;
        s.clear();
        lln div = pow(10, n);
        while(!s.count(k))
        {
            s.insert(k);
            temp = k * k;
            if(temp >= div)
            {
                int digit = log10(temp) +1;
                lln mod = pow(10, digit - n);
                k = temp / mod;
                // k = temp / (lln)pow(10, digit);
            }
            else
                k = temp;
            mm = max(mm, k);
        }

        printf("%lld\n", mm);
    }
    return 0;
}

floyd判圈

速度飞快,0.5

c#include <cstdio>
#include <iostream>
using namespace std;

#define lln long long 
int buf[10];
int next(int n, int k) {
    if(!k) return 0;
    lln k2 = (lln) k * k;
    int L = 0;
    while(k2 > 0) { buf[L++] = k2 %10; k2 /= 10; }
    if(n > L) n = L;
    int ans = 0;
    for(int i = 0; i < n;i ++)
        ans = ans * 10 + buf[--L];
    return ans;
}

int main()
{
    int T;
    cin >> T;
    while(T--) {
        int n, k;
        cin >> n >> k;
        int ans = k;
        int k1 = k, k2 = k;
        do {
            k1 = next(n, k1);
            k2 = next(n, k2); if(k2 > ans) ans = k2;
            k2 = next(n, k2); if(k2 > ans) ans = k2;
        } while(k1 != k2);
        cout << ans << endl;
    }
    return 0;
}

svtter
209 声望37 粉丝

更喜欢原型开发