POJ 1845 Sumdiv (求某个数的所有正因子的和)
题意: 求A^B的所有正因子的和,最后模9901的结果。
思路:
若对一个数n进行素数分解,n=p1^a1*p2^a2*p3^a3*...*pk^ak
那么n的所有正因子之和sum=(1+p1+...+p1^a1)*(1+p2+...+p2^a2)*...*(1+pk+...+pk^ak)
然后可以用等比数列求和公式(pk^(ak+1)-1)/(pk-1)求每项的和,再累乘。
用等比数列求1+pk+...+pk^ak时候要注意几点:
1.这里有除法,所以模的时候要将除以分母转化成乘以分母的逆元
a = (b/c) ==> a%m = b*c^(m-2)%m ( m为素数 )
证明:
b = a * c
根据费马小定理 a^(p-1)= 1 %p;(p是素数且a不能整除p)
所以 c^(m-1)%m=1%m
因此 a % m = a*1%m = a * c^(m-1)%m = a*c*c^(m-2)%m = b*c^(m-2)%m;
2.等比求和公式要注意,分母pk-1不能为0。
当pk%mod=1的时候, (1+pk+...+pk^ak)%mod=ak+1
3.当pk%mod=0的时候,(1+pk+...+pk^ak)=1,可以直接pass即可
还有从discuss里看到别人求和的做法:
1.可以首先计算rem=p^(cB+1)%(MOD*(p-1))
2.然后计算rem=(rem-1+MOD*(p-1))/(p-1)
3.最后计算rem%MOD
这里MOD*(p-1)可能会超过32位,所以在计算p^(cB+1)%(MOD*(p-1))时候可能乘法会溢出....careful....
证明:
令t*(p-1)=(p^0+p^1+p^2+...+p^a)*(p-1)=p^(a+1)-1 (mod m*(p-1))
因为gcd(p-1,m*(p-1))=p-1且 (p-1)|p^(a+1)-1 ,所以t=(p^(a+1)-1)/(p-1) (mod m)
因此我们可以先求p^(a+1)-1 (mod m*(p-1)),再把这个值除以(p-1)后取mod m
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h> using namespace std;
long long A,B;
const int mod=;
const int maxn=;
bool isprime[maxn];
int prime[maxn];
int cnt=; void init(){
memset(isprime,true,sizeof(isprime));
for(int i=;i<maxn;i++){
if(isprime[i]){
prime[cnt++]=i;
for(int j=*i;j<maxn;j+=i)
isprime[j]=false;
}
}
}
long long quickPow(long long a,long long b){
long long ret=;
while(b){
if(b&)
ret=ret*a%mod;
a=a*a%mod;
b=b>>;
}
return ret;
}
long long solve(long long a,long long b){
int c;
long long ans=;
for(int i=;i<cnt;i++){
c=;
if(a%prime[i]==){
while(a%prime[i]==){
c++;
a=a/prime[i];
}
if(prime[i]%mod==)
continue;
else if(prime[i]%mod==){
//(1+p+p^2+...+p^cb),此时求和不能用等比,因为分母(p-1)!=0。模9901后的和为c+1
ans=(ans*(c*b+))%mod; //注意:是c*b+1,一开始写成了c+1。
}
else{
long long ret=(quickPow((long long)prime[i],(long long)(c*b+))-+mod)%mod;
ans=(ans*(ret*quickPow((long long)(prime[i]-),(long long)(mod-))%mod))%mod;
}
}
}
//不要忘记了最后的a若大于1,则为素因子
if(a>){
if(a%mod==)
return ans;
else if(a%mod==){
ans=(ans*(b+))%mod; //注意:由于这里c=1,所以是b+1,一开始写成了2,也忘记乘以b了。
}
else{
long long ret=(quickPow(a,(long long)(b+))-+mod)%mod;
ans=(ans*(ret*quickPow(a-,(long long)(mod-))%mod))%mod;
}
}
return ans;
}
int main()
{
init();
while(scanf("%I64d%I64d",&A,&B)!=EOF){
printf("%I64d\n",solve(A,B));
}
return ;
}
也可以用二分来求 1+p+...+p^m
1.当m=2*k时:
p+...+p^2k=(1+p^k)(p+p^2+...+p^k)
2.当m=2*k+1时:
p+...+p^2k+p^(2k+1)=(1+p^k)(p+p^2+...+p^k)+p^(2k+1)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm> using namespace std; const int maxn=;
int cnt,prilen;
long long A,B;
int shu[]; //存储质因数
int num[]; //存储相应的质因数个数 /**
用于处理n的质因数
*/
void eular(int n) {
memset(num,,sizeof(num));
int i;
cnt=;
for (i=; i*i<=n; i++) {
if (n%i==) {
cnt++;
n/=i;
shu[cnt]=i;
num[cnt]++;
while (n%i==) {
n/=i;
num[cnt]++;
}
}
}
if(n>){
cnt++;
shu[cnt]=n;
num[cnt]++;
}
}
//这里传入参数的a和b值要定义为long long,否则答案不对
long long quickPow(long long a,long long b) {
long long ans=;
while(b>) {
if(b&) {
ans=(ans*a)%;
}
a=(a*a)%;
b=b>>;
}
return ans;
}
/**
计算p+...+p^n;
*/
long long cal(long long p,long long n){
long long ans=;
if(n==)
return ;
if(n&){
ans=((cal(p,n-)%)+(quickPow(p,n)%))%;
}
else{
ans=(((+quickPow(p,n/))%)*(cal(p,n/)%))%;
}
return ans%;
} long long sum(){
long long ans=;
for(int i=;i<=cnt;i++){
ans=(ans*(+cal(shu[i],num[i]*B))%)%;
}
return ans%;
} int main() {
scanf("%lld%lld",&A,&B);
eular(A);
printf("%I64d\n",sum());
return ;
}
POJ 1845 Sumdiv (求某个数的所有正因子的和)的更多相关文章
- poj 1845 POJ 1845 Sumdiv 数学模板
筛选法+求一个整数的分解+快速模幂运算+递归求计算1+p+p^2+````+p^nPOJ 1845 Sumdiv求A^B的所有约数之和%9901 */#include<stdio.h>#i ...
- 算法笔记(c++)--求一个数的所有质数因子
算法笔记(c++)--求一个数的所有质数因子 先贴题目: 这题不难,恶心在理解上面.最后看评论知道了怎么回事: 2*2*3*3*5=180 按照这逻辑的话应该输入的数由一系列质数相乘出来,所以每次找到 ...
- poj 1845 Sumdiv (等比求和+逆元)
题目链接:http://poj.org/problem?id=1845 题目大意:给出两个自然数a,b,求a^b的所有自然数因子的和模上9901 (0 <= a,b <= 50000000 ...
- POJ 1845 Sumdiv(求因数和 + 逆元)题解
题意:给你a,b,要求给出a^b的因子和取模9901的结果. 思路:求因子和的方法:任意A = p1^a1 * p2^a2 ....pn^an,则因子和为sum =(1 + p1 + p1^2 + . ...
- poj 1845 Sumdiv 约数和定理
Sumdiv 题目连接: http://poj.org/problem?id=1845 Description Consider two natural numbers A and B. Let S ...
- POJ 1845 Sumdiv 【二分 || 逆元】
任意门:http://poj.org/problem?id=1845. Sumdiv Time Limit: 1000MS Memory Limit: 30000K Total Submissions ...
- POJ 1845 Sumdiv(逆元)
题目链接:Sumdiv 题意:给定两个自然数A,B,定义S为A^B所有的自然因子的和,求出S mod 9901的值. 题解:了解下以下知识点 1.整数的唯一分解定理 任意正整数都有且只有唯一的方式 ...
- POJ 1845 Sumdiv [素数分解 快速幂取模 二分求和等比数列]
传送门:http://poj.org/problem?id=1845 大致题意: 求A^B的所有约数(即因子)之和,并对其取模 9901再输出. 解题基础: 1) 整数的唯一分解定理: 任意正整数都有 ...
- POJ 1845 Sumdiv#质因数分解+二分
题目链接:http://poj.org/problem?id=1845 关于质因数分解,模板见:http://www.cnblogs.com/atmacmer/p/5285810.html 二分法思想 ...
随机推荐
- wpf 获取DataGrid某一个单元格,设置此单元格ToolTip内容和背景颜色
public void GetCell() { for (int i = 0; i < this.datagrid1.Items.Count; i++) ...
- WPF:将HTML RGB颜色值转化为Color对象的两种方式
(1)方式一: Color color1 = (Color)System.Windows.Media.ColorConverter.ConvertFromString("#E0E0E0&qu ...
- Media Player(APP)
今天共享一下,以前做的影音播放器.比较简单.适合新手. 我上传了附件可以参考一下. PDF:http://files.cnblogs.com/files/hongguang-kim/MediaPlay ...
- 使用ViewSwitcher和ViewFlipper在不同布局中切换
xml布局: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:androi ...
- Tutorial: Analyzing sales data from Excel and an OData feed
With Power BI Desktop, you can connect to all sorts of different data sources, then combine and shap ...
- Go实现线程池
本文通过代码讲解如何实现一个线程池.代码(来自https://gobyexample.com/)及注释如下: package main import "fmt" import &q ...
- openssl AES加密以及padding
好习惯,先上代码再说事 加密 void AesEncrypt(unsigned char* pchIn, int nInLen, unsigned char *ciphertext, int & ...
- [转]"error while loading shared libraries: xxx.so.x" 错误的原因和解决办法
[转]"error while loading shared libraries: xxx.so.x" 错误的原因和解决办法 http://blog.csdn.net/sahuso ...
- HTML QQ聊天代码 简单的一行代码
简单的一行代码: <a href="tencent://message/?uin=173007740&Site=&Menu=yes">和17300774 ...
- c++中-1是true呢还是false呢
今天想看一下引用c++中的,然后看到网上有问c++中-1是true or false呢?用vc6.0是了一下,是true.vc6.0中应该是非0的都是true,0为false.java我也试了一下,i ...