欧拉定理
第二天数论,简直听天书
记住就行
P4139:上帝与集合的正确用法:https://www.luogu.org/problemnew/show/P4139
考虑扩展欧拉定理,每次对上面的式子使用扩欧
由于对一个数不断取phi,当p为1返回0即可,所以复杂度为log(p)
考虑到原题中的式子一定比p大,所以只用考虑定理中的第二种情况即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include <ext/pb_ds/priority_queue.hpp> #include<queue> #include<map> using namespace std; typedef long long ll; #define pii pair<int,int> #define mp make_pair #define pair_heap __gnu_pbds ::priority_queue<pii> #define llinf 9000000000000000000LL #define B cout << "breakpoint" << endl; inline 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) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 1e7 + 5; ll pri[maxn],cnt,phi[maxn]; bool vis[maxn]; void init() { for(int i = 2;i <= maxn - 5;i++) { if(!vis[i]) pri[++cnt] = i,phi[i] = i - 1; for(int j = 1;j <= cnt && i * pri[j] <= maxn - 5;j++) { vis[i * pri[j]] = 1; if(i % pri[j] == 0) {phi[i * pri[j]] = phi[i] * pri[j]; break; } else phi[i * pri[j]] = phi[i] * phi[pri[j]]; } } } ll power(ll a,ll b,ll p) { ll ans = 1,res = a; while(b) { if(b & 1) (ans *= res) %= p; (res *= res) %= p; b >>= 1; } return ans; } ll solve(ll p) { if(p == 1) return 0; return power(2,solve(phi[p]) + phi[p],p); } int main() { ll t = read(); init(); while(t--) { ll p = read(); printf("%lld\n",solve(p)); } }
CF906D:power tower:https://www.luogu.org/problemnew/show/CF906D
继续用欧拉定理,和上面一样,至多递归log层结束
不一样的是,这道题需要考虑b与phi(p)的大小关系
有两种解决方法:1.记录b是否真正被phi(p)模过,返回pair即可
2.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
ll mod(ll a,ll b) { return a < b ? a : a % b + b; }
这样取模,结果虽然还是比b大(符合原来的情况),但是再取一遍模在计算时仍然可以得到正确答案
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<queue> #include<map> using namespace std; typedef long long ll; #define B cout << "breakpoint" << endl; inline 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) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 1e6 + 5; map<ll,ll> phi; ll n,p; ll a[maxn]; ll get(ll x) { ll res = x,tp = x; if(phi[x]) return phi[x]; for(int i = 2;i <= sqrt(x);i++) { if(x % i == 0) { res = res / i * (i - 1); while(x % i == 0) x /= i; } } if(x > 1) res = res / x * (x - 1); return phi[tp] = res; } ll mod(ll a,ll b) { return a < b ? a : a % b + b; } ll power(ll a,ll b,ll p) { ll ans = 1,res = a; while(b) { if(b & 1) ans = mod(ans * res, p); res = mod(res * res,p); b >>= 1; } return ans; } ll solve(int l,int r,ll p) { if(l == r || p == 1) return mod(a[l],p); else return power(a[l],solve(l + 1,r,get(p)),p); } int main() { n = read(); p = read(); for(int i = 1;i <= n;i++) a[i] = read(); ll q = read(); while(q--) { ll l = read(),r = read(); printf("%lld\n",solve(l,r,p) % p); } }