题目背景较多,读完题之后,发现其实就是要写一个程序来计算$$2^{year-1} % 1000000007$$

题目要求一次计算不超过1s才能得满分,而year-1的值非常大。

显然无法使用暴力的pow(2,year-1)%1000000007来计算答案,题目提示结合密码学的相关知识,于是可以判断出有相关的数学方法可以帮助计算。

<!-- more -->

如果学过RSA公钥加密算法,应该对 费马小定理 及其推广 欧拉定理 有所了解。

欧拉定理,是一个关于同余的性质。

欧拉定理表明,若n,a为正整数,且n,a互质,即n和a最大公约数是1。那么有: $$a^{\varphi(n)} \equiv 1\space (mod{\space}n)$$

其中,$\varphi(n)$是欧拉函数,其值是小于或等于n的正整数中与n互质的数的数量。

而在本题中,令a是2,显然a是一个质数;令n是1000000007,也是一个质数。a和n显然互质。

将其带入欧拉定理的等式,$$2^{\varphi(n)} \equiv 1\space (mod{\space}n)$$

由于1000000007是一个质数,小于或等于n的正整数中与他互质的数的数量显然是1000000006,因为只有1不与1000000007互质。 所以,可以得到$$2^{1000000006} \equiv 1\space (mod\space 1000000007)$$

现在回到本题,我们设year-1为m,于是题目变成求$2^m % 1000000007$的值。

有了上面的推导,可以把$2^m % 1000000007$分成$ 2^{1000000006} * 2^{1000000006} * \cdots * 2^k$

其中k是m%1000000006的值,这里需要编程写一下大数取模。

之后就是对$2^k%1000000007$的计算,其中k是一个小于$10^9+6$的正整数。

这里如果直接使用pow(2,k) %1000000007的话,1次计算的运行时间会超过1s。也就是说,如果解题到此处,并提交key,可以得到200分。那么如何得到最后100分呢?

这里可以使用快速幂模算法,这是一个密码学及数论中很常见的运算技巧,来计算便可以很快得到答案,满分!

标准代码:

#include <bits/stdc++.h>
#define MOD 1000000007
#define MAD 1000000006
char str[200000],num[200000];
int t[200000],tonum[200000];
int main()
{
    freopen("out.txt","r",stdin);
    scanf("%s",str);
    int ori=10,to=2;
    int i,j=0,len=strlen(str),k=len,tt=len-1;
    /// 处理减1
    if (str[tt] != '0')
        str[tt]--;
    else
    {
        while (str[tt] == '0')
            tt--;
        str[tt]--;
        for (i=tt+1; i<len; i++)
        {
            str[i]='9';
        }
    }
    /// 计算year-1 % MOD
    int st=0;
    long long t,s;
    s=0;
    while (str[st] == '0')
        st++;
    str[len]='\0';
    for (i=st; i<len; i++)
    {
        s=s*10+str[i]-'0';
        s=s%MAD;
    }
    /// 快速幂
    long long ans=1;
    long long mul=2;
    while (s != 0)
    {
        if ((s&1) == 1)
            ans=ans*mul%MOD;
        mul=mul*mul%MOD;
        s>>=1;
    }
    printf("%I64d\n",ans);
    return 0;
}