ACM-数论-广义欧拉降幂
https://www.cnblogs.com/31415926535x/p/11447033.html
曾今一时的懒,造就今日的泪
记得半年前去武大参加的省赛,当时的A题就是一个广义欧拉降幂的板子题,后来回来补了一下,因为没有交的地方,于是就测了数据就把代码扔了,,,然后,,昨天的南京网络赛就炸了,,,一样的广义欧拉降幂的板子题,,然后因为忘记了当初自己想出来的那中写法,,一直想着回想起之前的写法,,然后到结束都没弄出来,,,emmmm,,
赛后看了一下别人的解法,,别人的处理方法很巧妙,,当然另一个种返回两个值的(pair)的解法就是武大的标程,,,,(到最后之前想出的写法还是每能推出来,,都开始怀疑自己当时有没有真的推出来,,,,,
思路
广义欧拉降幂没啥好说的,,就是那个公式:
$$
对于求 a^b(mod p)可以转换为:
a^b = \begin{cases}
a^{b \% \phi (p)} &gcd(a, p)=1 \\
a^b &gcd(a, p) \neq 1, b < \phi (p) \\
a^{b \% \phi (p) + \phi (p)} &gcd(a, p) \neq 1, b \ge \phi (p)
\end{cases}
$$
公式很简单,,但是如果是求 \(a_1^{a_2^{a_3^{...}}} (mod \ p)\) 类似这样的值的话,显然要递归从上往下求(刚开始弄成了从下往上求,,口胡了一段时间,,,,),,但是再递归求的时候要考虑每一次 \(b\) 和 \(\phi (p)\) 的关系,,然后选择哪一个等式,,,这样就麻烦了,,可以用一个 pair 什么的来保存一个标志变量来决定递归的上一层要不要 \(+ \phi (p)\) ,,另一种巧妙地方式是修改一下 取模 的过程,,这样就不用考虑了,,,具体的推导过程在这里
所有的取模的步骤改成这样:
inline ll modulo(ll x, ll mod){return x < mod ? x : x % mod + mod;}
这样保证 \(b \ge \phi (p)\),,然后就少了判断的情况
题目
南京网络赛B supper_log
这道题按题目的意思推几项样例就能看出是要求一个 \(a^{a^{a^{a^{...}}}} mod \ m (一共有b个a)\) 的值,,直接降幂求就可以了,, 记得特判 b=0 的情况
代码
群里很多大佬用的方法,重置取模的流程
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const double pi = 3.14159265358979;
const int maxn = 1e3 + 5;
const int maxm = 1e3 + 5;
const int mod = 1e9 + 7;
ll f(ll x, ll a)
{
if(x < 1)return -1;
return 1 + f((ll)(log(x) / log(a)), a);
}
inline ll modulo(ll x, ll mod){return x < mod ? x : x % mod + mod;}
inline ll pow_(ll a, ll b, ll p)
{
ll ret = 1;
while(b)
{
if(b & 1)ret = modulo(ret * a, p);
a = modulo(a * a, p);
b >>= 1;
}
return ret;
}
inline ll phi(ll x)
{
ll ans = x;
for(ll i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x % i == 0)x /= i;
}
}
if(x > 1)ans = ans / x * (x - 1);
return ans;
}
ll gcd(ll a, ll b)
{
if(b == 0)return a;
return gcd(b, a % b);
}
ll f(ll a, ll b, ll k, ll p)
{
if(p == 1)return 1;
if(k == 0)return 1;
return pow_(a, f(a, a, k - 1, phi(p)), p);
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
// ios_base::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t; cin >> t;
while(t--)
{
ll a, b, m;
cin >> a >> b >> m;
// cout << a << b << m << endl;
if(b == 0)
{
cout << 1 % m << endl;
continue;
}
ll ans = f(a, a, b, m) % m;
// if(a == 1)ans = 1 % m;
// cout << ans << " " << ans % m << endl;
cout << ans << endl;
}
// cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
return 0;
}
pair记录上一层
武大那场的标程,,直接改了下输入,,
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1000010;
int prime[N + 1], isprime[N + 1];
int tot, phi[N + 1];
struct P
{
ll ans;
bool v;
P(ll _ans, bool _v)
{
ans = _ans;
v = _v;
}
};
ll gcd(ll a, ll b)
{
return b ? gcd(b, a % b) : a;
}
P qpow(ll A, ll B, ll C)
{
ll re = 1;
bool flag = 1;
while (B)
{
if (B & 1)
{
if ((re *= A) >= C)
flag = 0;
re = re % C;
}
B = B >> 1;
if (B)
{
if (A >= C)
flag = 0;
A %= C;
if ((A *= A) >= C)
flag = 0;
A %= C;
}
}
return P(re, flag);
}
void getphi()
{
phi[1] = 1;
isprime[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!isprime[i])
{
prime[++tot] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= tot && i * prime[j] <= N; j++)
{
isprime[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else
phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
}
inline ll Euler(ll x)
{
return phi[x];
//题目可以再复杂一点模数可以到longlong
// ll ans = x;
// for (int i = 1; i <= tot && prime[i] * prime[i] <= x; i++)
// {
// if (x % prime[i] == 0)
// {
// ans = ans / prime[i] * (prime[i] - 1);
// while (x % prime[i] == 0)
// x /= prime[i];
// }
// }
// if (x > 1)
// ans = ans / x * (x - 1);
// return ans;
}
P f(ll a, ll b, ll k, ll p)
{
if (p == 1)
return P(0, 0);
if (k == 0)
return P(a % p, a < p);
ll ep = Euler(p);
P tmp = f(b, b, k - 1, ep);
if (gcd(a, p) == 1)
return qpow(a, tmp.ans, p);
if (tmp.v == false)
{
tmp.ans += ep;
}
return qpow(a, tmp.ans, p);
}
int main()
{
//double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ll a, b, k, p;
getphi();
int t;
while (~scanf("%d", &t))
{
while (t--)
{
scanf("%lld %lld %lld", &a, &k, &p);
b = a;
if(k == 0)
{
printf("%lld\n", 1 % p);
continue;
}
printf("%lld\n", f(a, b, k - 1, p).ans);
}
}
//cout<<(clock()-pp)/CLOCKS_PER_SEC;
return 0;
}
cf-906 D. Power Tower
突然很多人交这道两年前的题啊,,hhhhh
这题也是降幂,他是求的一个指数序列的一个区间的幂的值,,,套路一样,,就是这个模数很大,,不能每次都算他的 phi ,,不然会超时,,所以要记忆化一下 unordered_map 一下,,或者 预处理一下模数的所有phi 因为对一个数一直求 phi 下去,,其实个数不多,,,
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const double pi = 3.14159265358979;
const int maxn = 1e5 + 5;
const int maxm = 1e3 + 5;
const int mod = 1e9 + 7;
ll a[maxn];
inline ll modulo(ll x, ll mod){return x < mod ? x : x % mod + mod;}
inline ll pow_(ll a, ll b, ll p)
{
ll ret = 1;
while(b)
{
if(b & 1)ret = modulo(ret * a, p);
a = modulo(a * a, p);
b >>= 1;
}
return ret;
}
unordered_map<ll, ll> phi_;
inline ll phi(ll x)
{
if(phi_[x])return phi_[x];
ll ans = x;
ll t = x;
for(ll i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x % i == 0)x /= i;
}
}
if(x > 1)ans = ans / x * (x - 1);
phi_[t] = ans;
return ans;
}
//这里根据题意来更改,k表示共有k个指数
ll f(ll a, ll b, ll k, ll p)
{
if(p == 1)return 1;
if(k == 0)return 1;
return pow_(a, f(a, a, k - 1, phi(p)), p);
}
ll f(ll l, ll r, ll p)
{
if(p == 1)return 1;
if(l == r + 1)return 1;
return pow_(a[l], f(l + 1, r, phi(p)), p);
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
ll n, m;
cin >> n >> m;
for(int i = 1; i <= n; ++i)cin >> a[i];
int q; cin >> q;
while(q--)
{
ll l, r; cin >> l >> r;
cout << f(l, r, m) % m << endl;
}
// cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
return 0;
}
cf-gym-101550 E Exponial
这题是求一个 \(n^{{n-1}^{{n-2}^{{n-3}^{{...}^{1}}}}} mod \ p\) ,,,用上面的板子改一改就可以了,,,
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(time(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-7;
const double pi = 3.14159265358979;
const int maxn = 1e5 + 5;
const int maxm = 1e3 + 5;
const int mod = 1e9 + 7;
inline ll modulo(ll x, ll mod){return x < mod ? x : x % mod + mod;}
inline ll pow_(ll a, ll b, ll p)
{
ll ret = 1;
while(b)
{
if(b & 1)ret = modulo(ret * a, p);
a = modulo(a * a, p);
b >>= 1;
}
return ret;
}
unordered_map<ll, ll> phi_;
inline ll phi(ll x)
{
if(phi_[x])return phi_[x];
ll ans = x;
ll t = x;
for(ll i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
ans = ans / i * (i - 1);
while(x % i == 0)x /= i;
}
}
if(x > 1)ans = ans / x * (x - 1);
phi_[t] = ans;
return ans;
}
// ll f(ll l, ll r, ll p)
// {
// if(p == 1)return 1;
// if(l == r + 1)return 1;
// return pow_(a[l], f(l + 1, r, phi(p)), p);
// }
ll f(ll a, ll p)
{
if(p == 1)return 1;
if(a == 1)return 1;
return pow_(a, f(a - 1, phi(p)), p);
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
ll n, m;
while(cin >> n >> m)cout << f(n, m) % m << endl;
// cout << endl << (clock() - pp) / CLOCKS_PER_SEC << endl;
return 0;
}
貌似够了,,,数论是最不想碰的东西,,emmmm,,,但又时不得不稍稍掌握的东西,,,,
(end....)
ACM-数论-广义欧拉降幂的更多相关文章
- Power Tower(广义欧拉降幂)
题意:https://codeforc.es/contest/906/problem/D 计算区间的: ai ^ ai+1 ^ ai+2.......ar . 思路: 广义欧拉降幂: 注意是自下而上递 ...
- 广义欧拉降幂(欧拉定理)——bzoj3884,fzu1759
广义欧拉降幂对于狭义欧拉降幂任然适用 https://blog.csdn.net/qq_37632935/article/details/81264965?tdsourcetag=s_pctim_ai ...
- Codeforces Round #454 D. Power Tower (广义欧拉降幂)
D. Power Tower time limit per test 4.5 seconds memory limit per test 256 megabytes input standard in ...
- The Preliminary Contest for ICPC Asia Nanjing 2019 B. super_log (广义欧拉降幂)
In Complexity theory, some functions are nearly O(1)O(1), but it is greater then O(1)O(1). For examp ...
- BZOJ 3884——欧拉降幂和广义欧拉降幂
理论部分 欧拉定理:若 $a,n$ 为正整数,且 $a,n$ 互质,则 $a^{\varphi (n)} \equiv 1(mod \ n)$. 降幂公式: $$a^b=\begin{cases}a^ ...
- Codeforces Round #454 (Div. 1) CodeForces 906D Power Tower (欧拉降幂)
题目链接:http://codeforces.com/contest/906/problem/D 题目大意:给定n个整数w[1],w[2],……,w[n],和一个数m,然后有q个询问,每个询问给出一个 ...
- 2018牛客网暑期ACM多校训练营(第四场) A - Ternary String - [欧拉降幂公式][扩展欧拉定理]
题目链接:https://www.nowcoder.com/acm/contest/142/A 题目描述 A ternary string is a sequence of digits, where ...
- 数学--数论--欧拉降幂--P5091 欧拉定理
题目背景 出题人也想写有趣的题面,可惜并没有能力. 题目描述 给你三个正整数,a,m,ba,m,ba,m,b,你需要求:ab mod ma^b \bmod mabmodm 输入格式 一行三个整数,a, ...
- hdu 1286:找新朋友(数论,欧拉函数)
找新朋友 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
随机推荐
- 林大妈的JavaScript基础知识(三):JavaScript编程(1)对象
1. 对象的简单介绍与一些注意事项 JavaScript中具有几个简单数据类型:数字.字符串.布尔值.null值以及undefined值.除此之外其余所有值(包括数组.函数,甚至正则表达式)都是对象. ...
- 手撸PHP数据库连接
最近这个月过得确实有点狼狈....不停地复习,看书..终于到今天为止考完了2科了.能让我好好地写写博客了..前段时间的PHP课设我多学了点东西,在我们一般老师讲的php连接数据库方面做了一些优化.前段 ...
- git远程服务器回滚
1.git log查找commit hash 2.git reset --hard hash 回滚本地git库 3.git push -f origin(git仓库的url) branch名 强制提交
- 雪花算法【分布式ID问题】【刘新宇】
分布式ID 1 方案选择 UUID UUID是通用唯一识别码(Universally Unique Identifier)的缩写,开放软件基金会(OSF)规范定义了包括网卡MAC地址.时间戳.名字空间 ...
- Linux 常用命令及使用方法
1. type :查询命令 是否属于shell解释器 2. help : 帮助命令3. man : 为所有用户提供在线帮助4. ls : 列表显示目录内的文件及目录 -l 以长格 ...
- H3C模拟器单臂路由配置实例
单臂路由:用802.1Q和子接口实现VLAN间路由 单臂路由利用trunk链路允许多个VLAN的数据帧通过而实现 网络拓扑图: RTA配置: SW1配置: PC1/2配置如图: 但是值得注意的是,在配 ...
- 数字麦克风PDM信号采集与STM32 I2S接口应用(二)
在使用STM32的数字麦克风I2S接口时,计算采样率让人头疼,芯片手册上没有明确的说法,而手册上的计算方法经过测试确和实验不符.借助搜索引擎,大部分资料都是来自于开发板卖家或开发板论坛,主要是咪头采集 ...
- 【Java例题】3.5 级数之和
5. 计算级数之和: y=3*1!/1-3^2*2!/2^2+3^3*3!/3^3-...+ (-1)^(n-1)*3^n*n!/n^n. 这里的"^"表示乘方,"!&q ...
- Docker启用TLS进行安全配置
之前开启了docker的2375 Remote API,接到公司安全部门的要求,需要启用授权,翻了下官方文档 Protect the Docker daemon socket 启用TLS 在docke ...
- 数据结构之队列C++版
#include "stdafx.h"/* 队列是一种先进先出的线性表队列的核心是对头部和尾部索引的操作 如上图所示,当对头索引移动到最前面6,队尾又不不再末尾0的位置,那么如果不 ...