zoukankan      html  css  js  c++  java
  • 上帝与集合的正确用法

    传送门

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

    一句话描述题意就是求无限个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('
    ')
    #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
    ",solve(n));
        return 0;
    }
  • 相关阅读:
    Linux 安装Zookeeper<集群版>(使用Mac远程访问)
    04寻找两个数组的中位数
    28实现strSTR()
    125验证回文串
    124,二叉树中的最大路径和
    123买卖股票的最佳时机III
    02爬取豆瓣最受欢迎的250部电影
    01爬取当当网500本五星好评书籍
    112买卖股票的最佳时机II
    121.买卖股票的最佳时机
  • 原文地址:https://www.cnblogs.com/captain1/p/9781355.html
Copyright © 2011-2022 走看看