码迷,mamicode.com
首页 > 其他好文 > 详细

上帝与集合的正确用法

时间:2018-10-13 02:38:36      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:证明   欧拉   递推   ble   bsp   names   main   多次   ext   

传送门

这题出的真不是一般的好……

一句话描述题意就是求无限个2垒在你的指数上……求mod p的值,其中p不超过107

这玩意其实是一个递推函数(当然我们是递归求解的),我也不知道怎么拿语言描述233.

我们这题要用到欧拉降幂公式!

首先啥是欧拉降幂公式?

它的基本形式长这样:

Ak ≡ Ak%φ(m) + φ(m) (mod m) (k > φ(m))

Ak ≡ Ak (mod m) (k <= φ(m))

具体是怎么证明的……?这证明过程太长了,我只抄在了本上。我们可以看一下这位大佬的证明!传送门

嗯,然后我们就用它来解决问题,这个问题中底数永远是2,然后指数……因为是无限个2我们直接给他看成一样的吧!这样的话,对于每个k mod φ(m),这个数是可以递归计算的,这个式子本来是2k的形式,但是因为无限的2,所以其实k也可以表示为2k的形式……只是每次向下递归的时候模数会变。

我们可能会有疑惑,但是这个指数是无限的呀!我们什么时候能算完呢?

但是不要忘了,我们每次递归之后,用来取模的数会从m变成φ(m),所以不需要递归很多次我们就会算到模数为1的情况,这个时候直接返回0,然后这样递归回去就有解啦!所以我们只要处理出所以欧拉函数就行(直接求似乎也行)

顺便还学了一下快速乘2333,和快速幂挺像的,就是把乘法变成了加法.

看一下代码。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;
 
ll read()
{
    ll ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
    if(ch == -) op = -1;
    ch = getchar();
    }
    while(ch >=0 && ch <= 9)
    {
    ans *= 10;
    ans += ch - 0;
    ch = getchar();
    }
    return ans * op;
}

ll T,n,pri[N],phi[N],tot;
bool np[N];

ll qmul(ll a,ll b,ll mod)
{
    ll p = 0;
    while(b)
    {
    if(b&1) p = (p + a) % mod;
    a = (a + a) % mod;
    b >>= 1;
    }
    return p;
}

ll qpow(ll a,ll b,ll mod)
{
    ll p = 1;
    while(b)
    {
    if(b&1) p *= a,p %= mod;
    a *= a,a %= mod;
    b >>= 1;
    }
    return p;
}

void euler()
{
    np[1] = 1;
    rep(i,2,N-5)
    {
    if(!np[i]) pri[++tot] = i,phi[i] = i - 1;
    for(int j = 1;i * pri[j] <= N-5;j++)
    {
        np[i * pri[j]] = 1;
        if(!(i % pri[j]))
        {
        phi[i * pri[j]] = phi[i] * pri[j];
        break;
        }
        else phi[i * pri[j]] = phi[i] * (pri[j] - 1);
    }
    }
}

ll solve(ll mod)
{
    if(mod == 1) return 0;
    else return qpow(2,solve(phi[mod])+phi[mod],mod);
}

int main()
{
    euler();
    T = read();
    while(T--) n = read(),printf("%lld\n",solve(n));
    return 0;
}

 

上帝与集合的正确用法

标签:证明   欧拉   递推   ble   bsp   names   main   多次   ext   

原文地址:https://www.cnblogs.com/captain1/p/9781355.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!