上帝与集合的正确用法
Posted captain1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了上帝与集合的正确用法相关的知识,希望对你有一定的参考价值。
这题出的真不是一般的好……
一句话描述题意就是求无限个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; }
以上是关于上帝与集合的正确用法的主要内容,如果未能解决你的问题,请参考以下文章