您的位置:首页 > 其它

POJ 1845 Sumdiv(逆元或者二分求解等比数列)

2017-01-05 17:25 423 查看

题目分析

本题是求AB所有因子和对9901取模后的值。我们可以将A进行拆分。A=pk11∗pk22∗pk33.......∗pknn那么可以得到AB=pk1B1∗pk2B2∗pk3B3.......∗pknBn,于是所有因子和等于:(1+p1+p21+...+pk1B1)∗(1+p2+p22+...+pk2B2)∗...∗(1+pn+p2n+...+pknBn)

二分法

(1+a+a2+a3+......+an) 当n为奇数时可以化为:(1+a(n+1)/2)∗(1+a+......+a(n−1)/2),当n为偶数时可以化为:(1+an/2)∗(1+a+......+a(n−1)/2),然后递归求解即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 9901;
const int maxn = 1e5+100;
#define LL long long
LL prime[maxn], vis[maxn], tot;

void init(){  //构造素数表
tot = 0;
memset(vis, 0, sizeof(vis));
for(LL i = 2; i < maxn; i++) if(!vis[i]){
prime[tot++] = i;
for(LL j = i*i; j < maxn; j += i) vis[j] = 1;
}
}

LL quick_pow(LL a, LL b){ //快速幂
int ret = 1;
a %= mod;
while(b){
if(b&1) ret = (ret*a)%mod;
b >>= 1;
a = (a*a)%mod;
}
return ret;
}

LL solve(LL a, LL n){  //对于等比数列递归求解
if(n == 0) return 1;
LL t = solve(a, (n-1)/2);
if(n&1){
LL cur = quick_pow(a, (n+1)/2);
t = (t + t*cur%mod)%mod;
}
else{
int cur = quick_pow(a, n/2);
t = (t + t*cur%mod)%mod;
t = (t + quick_pow(a, n))%mod;
}
return t;
}

int main(){
init();
LL a, b;
while(scanf("%lld%lld", &a, &b) != EOF){
if(a == 0) printf("0\n");
else if(a == 1) printf("1\n");
else{
LL ans = 1;
for(int i = 0; i < tot; i++) if(a%prime[i] == 0){
int cnt = 0;
while(a%prime[i] == 0){
cnt++;
a /= prime[i];
}
ans = ans*solve(prime[i], cnt*b)%mod;
}
if(a != 1) ans = ans*solve(a, b)%mod;
printf("%lld\n", ans);
}
}
return 0;
}


第二种就是利用逆元求解

这道题我开始一直用扩展欧几里得进行求解,一直出不来,后来发现9901虽然是个素数,但是有可能另一个数是9901的倍数,那么这样肯定是错的,因此只能使用另一种求逆元的方法,即:(a/b)modm=amod(b∗m)/b,但是更奇葩的东西发生了,因此b*m会很大,因此在求快速幂的时候会爆long long,于是需要快速乘,快速乘实际上和快速幂并没有什么区别,看一下很好理解。。

#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int mod = 9901;
map <LL, LL> res;

LL multi(LL a, LL b, LL m){
LL ans = 0;
a %= m;
while(b){
if(b&1){
ans = (ans + a)%m;
b--;
}
b >>= 1;
a = (a+a)%m;
}
return ans;
}

LL quick_pow(LL a, LL b, LL M){
LL ret = 1;
a %= M;
while(b){
if(b&1) ret = multi(ret, a, M);
b >>= 1;
a = multi(a, a, M);
}
return ret;
}

void prime_factor(LL n){
LL m = sqrt(n+0.5);
res.clear();
for(LL i = 2; i <= m; i++){
while(n%i == 0){
++res[i];
n /= i;
}
}
if(n != 1) ++res
;
}

int main(){
LL a, b;
while(scanf("%lld%lld", &a, &b) != EOF){
if(a == 0) printf("0\n");
else if(a == 1) printf("1\n");
else{
prime_factor(a);
LL ans = 1;
for(map <LL, LL>::iterator it = res.begin(); it != res.end(); it++){
LL first = it->first;
LL second = it->second;

LL M = (LL)(first-1)*mod;
ans = ans*(quick_pow(first, second*b+1, M) + M - 1)/(first-1);
ans = ans%mod;
}
printf("%lld\n", ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: