POJ 1845 Sumdiv (逆元 等比数列求和)
2017-03-10 19:46
295 查看
今天我们来探讨逆元在ACM-ICPC竞赛中的应用,逆元是一个很重要的概念,必须学会使用它。
对于正整数
和
,如果有
,那么把这个同余方程中
的最小正整数解叫做
模
的逆元。
逆元一般用扩展欧几里得算法来求得,如果
为素数,那么还可以根据费马小定理得到逆元为
。
推导过程如下
求现在来看一个逆元最常见问题,求如下表达式的值(已知
)
当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果
是素数,还可以用费马小定理。
但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求
与
互素。实际上我们还有一
种通用的求逆元方法,适合所有情况。公式如下
现在我们来证明它,已知
,证明步骤如下
接下来来实战一下,看几个关于逆元的题目。
题目:http://poj.org/problem?id=1845
题意:给定两个正整数
和
,求
的所有因子和对9901取余后的值。
分析:很容易知道,先把
分解得到
,那么得到
,那么
的所有因子和的表达式如下
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int MOD = 9901;
int vis[10000];
vector<int> pri;
vector<P> Div;
ll mul(ll a, ll n, ll k) {
if(n == 0) return 0;
if(n == 1) return a % k;
ll ans = mul(a, n/2, k);
ans += ans;
if(n & 1) ans += a;
return ans % k;
}
ll pow(ll a, ll n, ll mod) {
if(n == 0) return 1;
ll ans = pow(a, n/2, mod);
ans = mul(ans, ans, mod);
if(n & 1) ans *= a % mod;
return ans % mod;
}
void get_Prime() {
int n = (int)sqrt((double)50000005);
for(int i = 2; i <= n; i++)
for(int j = i*2; j <= n; j += i)
vis[j] = 1;
for(int i = 2; i <= n; i++) if(!vis[i])
pri.push_back(i);
}
void get_div(ll x) {
for(int i = 0; i < pri.size(); i++) {
if(x % pri[i] == 0) {
int num = 0;
while(x % pri[i] == 0) {
x /= pri[i];
++num;
}
Div.push_back(P(pri[i], num));
}
}
if(x != 1) Div.push_back(P(x, 1));
}
ll cal(ll p, ll n) { // a + a^1 + a^2 + a^3 + ... ... + a^n
n++;
ll M = (p-1)*MOD;
return (pow(p, n, M) + M - 1) / (p - 1);
}
int main() {
ll A, B;
cin >> A >> B;
get_Prime();
get_div(A);
ll sum = 1;
for(int i = 0; i < Div.size(); i++) {
sum *= cal(Div[i].first, Div[i].second*B)%MOD;
sum %= MOD;
}
cout << sum << endl;
return 0;
}
对于正整数
和
,如果有
,那么把这个同余方程中
的最小正整数解叫做
模
的逆元。
逆元一般用扩展欧几里得算法来求得,如果
为素数,那么还可以根据费马小定理得到逆元为
。
推导过程如下
求现在来看一个逆元最常见问题,求如下表达式的值(已知
)
当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果
是素数,还可以用费马小定理。
但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求
与
互素。实际上我们还有一
种通用的求逆元方法,适合所有情况。公式如下
现在我们来证明它,已知
,证明步骤如下
接下来来实战一下,看几个关于逆元的题目。
题目:http://poj.org/problem?id=1845
题意:给定两个正整数
和
,求
的所有因子和对9901取余后的值。
分析:很容易知道,先把
分解得到
,那么得到
,那么
的所有因子和的表达式如下
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int MOD = 9901;
int vis[10000];
vector<int> pri;
vector<P> Div;
ll mul(ll a, ll n, ll k) {
if(n == 0) return 0;
if(n == 1) return a % k;
ll ans = mul(a, n/2, k);
ans += ans;
if(n & 1) ans += a;
return ans % k;
}
ll pow(ll a, ll n, ll mod) {
if(n == 0) return 1;
ll ans = pow(a, n/2, mod);
ans = mul(ans, ans, mod);
if(n & 1) ans *= a % mod;
return ans % mod;
}
void get_Prime() {
int n = (int)sqrt((double)50000005);
for(int i = 2; i <= n; i++)
for(int j = i*2; j <= n; j += i)
vis[j] = 1;
for(int i = 2; i <= n; i++) if(!vis[i])
pri.push_back(i);
}
void get_div(ll x) {
for(int i = 0; i < pri.size(); i++) {
if(x % pri[i] == 0) {
int num = 0;
while(x % pri[i] == 0) {
x /= pri[i];
++num;
}
Div.push_back(P(pri[i], num));
}
}
if(x != 1) Div.push_back(P(x, 1));
}
ll cal(ll p, ll n) { // a + a^1 + a^2 + a^3 + ... ... + a^n
n++;
ll M = (p-1)*MOD;
return (pow(p, n, M) + M - 1) / (p - 1);
}
int main() {
ll A, B;
cin >> A >> B;
get_Prime();
get_div(A);
ll sum = 1;
for(int i = 0; i < Div.size(); i++) {
sum *= cal(Div[i].first, Div[i].second*B)%MOD;
sum %= MOD;
}
cout << sum << endl;
return 0;
}
相关文章推荐
- poj 1845 Sumdiv 数论--等比数列和(逆元或者递归)
- POJ 1845 Sumdiv(逆元或者二分求解等比数列)
- POJ 1845 Sumdiv(约数和公式+等比数列求和)
- POJ-1845-Sumdiv 等比数列求和/数学/(二分法/逆元法/变换取模法)
- poj1845 sumdiv 整数唯一分解,等比数列求和或逆元
- POJ 1845 Sumdiv 逆元 费马小定理 Trick
- POJ 1845 Sumdiv(逆元)
- poj-1845 Sumdiv (逆元+费马小定理+因子和)
- POJ1845 Sumdiv【快速模幂+素因子分解+等比数列+二分法】
- POJ 1845 Sumdiv(逆元、分治)【真心好题啊=_=】
- POJ 1845 Sumdiv(质因数分解+快速幂+二分法求等比数列的和)
- poj 1845 Sumdiv 素数筛+快速幂求逆元+二分乘法
- POJ 1845 Sumdiv <数论(逆元 / 二分递归)>
- poj1845 Sumdiv(数论,因数和,等比数列,快速幂)
- POJ - 1845 Sumdiv 【约数个数定理 + 约数和定理 + 快速幂 + 逆元】
- 【POJ 1845】 Sumdiv (整数唯分+约数和公式+二分等比数列前n项和+同余)
- poj 1845 Sumdiv(求逆元)
- POJ 1845:Sumdiv 快速幂+逆元
- POJ Sumdiv (数论+二分等比数列求和)
- POJ-1845 Sumdiv 逆元,特殊情况