The beginning of the end (scrolling array, memoized search)

any door

The beginning of the end

topic background

The starting point is finally over,
the period is finally being written,
we are finally saying goodbye,
and finally we are back where we started
...

Each OIer's competition career always starts with a NOIp, and most of them end in a NOIp, as if reincarnation is constantly being staged.
If this NOIp is your starting point, I wish your OI career a splendid summer.
If this NOIp is your end, then may your OI memories shine like stars.
Maybe this is the last time you'll play on LA, maybe not.
Anyway, best of luck to you in the next week.

Of course, this question is also related to reincarnation.

topic description

The well-known Fibonacci sequence fib ( n ) \mathrm{fib}(n)fib ( n ) is calculated like this

That is 0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 ⋯ 0, 1, 1, 2, 3, 5, 8, 13 \cdots0,1,1,2,3,5,8,13 , each term is the sum of the previous two terms.

Little F found that if each item of the Fibonacci sequence is arbitrarily greater than 1 11 positive integerMMWhen M is modulo, the sequence will generate a cycle.

Of course, little F quickly understood, because ( fib ( n − 1 ) mod M \mathrm{fib}(n - 1) \bmod Mfib(n1)modM) 和 ( f i b ( n − 2 )   m o d   M ) \mathrm{fib}(n - 2) \bmod M) fib(n2)modM ) is only at mostM 2 M^2M2 values, so inM ​​2 M^2MThere must be a cycle after 2 calculations.

Even more generally, we can show that no matter what modulus MMM , final modulusMMThe Fibonacci sequence under M will be 0 , 1 , ⋯ , 0 , 1 , ⋯ 0, 1, \cdots, 0, 1, \cdots0,1,,0,1,

Now, given you a modulus MMM , please find the smallestn > 0 n > 0n>0 , so thatfib ( n ) mod M = 0 , fib ( n + 1 ) mod M = 1 \mathrm{fib}(n) \bmod M = 0 , \mathrm{fib}(n + 1) \bmod M = 1fib(n)modM=0,fib(n+1)modM=1

input format

Enter a line with a positive integer MMM

output format

Output a line with a positive integer nnn

Example #1

Sample Input #1

2

Sample output #1

3

Example #2

Sample Input #2

6

Sample output #2

24

hint

Example 1 Explanation

The Fibonacci sequence is 0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , ⋯ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, \cdots0,1,1,2,3,5,8,13,21,34, , in pair2 22 After taking the modulus, the result is0 , 1 , 1 , 0 , 1 , 1 , 0 , 1 , 1 , 0 , ⋯ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, \cdots0,1,1,0,1,1,0,1,1,0,

We can find that when n = 3 n = 3n=3rd ,f (n) mod 2 = 0, f (n + 1) mod 2 = 1 f(n) \bmod 2= 0, f(n + 1) \bmod 2 =f(n)mod2=0,f(n+1)mod2=1 , which is the nnwe requireThe minimum value of n .

data range

For 30% 30\%30% of the data,M ≤ 18 M \leq 18M18

For 70 % 70\%70% of the data,M ≤ 2018 M \leq 2018M2018

For 100 % 100\%100% of the data,2 ≤ M ≤ 706150 = 2 \leq M \leq 706150=2M706150=0xAC666

hint

If you don't know what is modulo ( mod ) (\bmod)(mod) , then I am also happy to tell you that the modulo operation is to find the remainder obtained by integer division, which is the final "indivisible" part of vertical division, that is, a
mod M = k ⟺ a = b M + k ( M > 0 , 0 ≤ k < M ) a \bmod M =k \iff a = bM + k\ (M > 0, 0 \leq k < M)amodM=ka=bM+k (M>0,0k<M )
of whicha , b , ka, b, ka,b,k are all non-negative integers.

If you use C/ C++, you can use %to do modulo arithmetic.

If you use Pascal, you can use modto do modulo arithmetic.

This problem is very easy to RE, one is to take the modulus, otherwise it is easy to RE, and then tell you the size of m, but you can't determine the minimum size of n, if it is m*m, then the array will be Will explode, the best way is to use rolling array. Of course, you can also memorize the search, so that you only use recursion instead of space.

My wrong approach:

Only 80 points were scored because the last two test samples were RE, and it should be that n may be very large.

#include<bits/stdc++.h>

using namespace std;

const int N=706155;
int f[N];
int m;

void fib()
{
    
    
    for(int i=2;i<N;i++)
        f[i]=(f[i-1]+f[i-2])%m;
}


int main()
{
    
    
    scanf("%d",&m);
    f[0]=0,f[1]=1;
    fib();
    for(int i=1;i<m*m;i++)
    {
    
    
        if(f[i]==0&&f[i+1]==1)
        {
    
    printf("%d",i);return 0;}
    }

    return 0;
}

Solution 1—memoization search Positive solution:

#include<cstdio>
typedef long long ll;
using namespace std;
const ll INF=0x7fffffff;
ll fp[10000002];//记忆数组,虽然m不大但是不知道n多大,尽量开大,不过1千万差不多极限
ll m;
ll f(ll i)
{
    
    
    if(fp[i])return fp[i];//调取记忆
    if(i==1||i==2)return fp[i]=1%m;
    else return fp[i]=(f(i-1)+f(i-2))%m;//这时就顺带%m可以使主程序更简单
}
int main()
{
    
    
    scanf("%lld",&m);
    ll i=1;//枚举
    while(f(i)!=0||f(i+1)!=1)//题目要求
    {
    
    
        i++;
    }
    printf("%lld",i);
    return 0;
}

Solution 2 - rolling array

Because we only consider whether these two numbers meet our requirements each time, and then these two numbers are related to the next number, so we'd better use a rolling array to save these three numbers.

#include<iostream>
#include<cstdio>
using namespace std;
int fi[5],m;
int main()
{
    
    
    scanf("%d",&m);
    fi[1]=0; fi[2]=1;
    for(int i=1;;i++)
    {
    
    
        fi[3]=(fi[1]+fi[2])%m;
        if(fi[2]==0&&fi[3]==1)
        {
    
    
            printf("%d\n",i);
            return 0;
        }
        fi[1]=fi[2]; fi[2]=fi[3];
    }
}

Guess you like

Origin blog.csdn.net/qq_51408826/article/details/127561647