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 二分法思想 ...
随机推荐
- [转]pro*c/c++编译错误 ” error: sqlca.h: No such file or directory “ 的解决办法
$ gcc -o test test.c 出现错误:error: sqlca.h: No such file or directory [解决方法]知道 sqlca.h 在 $ORACLE_HOME/ ...
- 配置DB2的数据库ODBC连接
打开cmd窗口,输入db2cmd启动db2 clp窗口 输入db2 list node directory查看是否有数据库需要连接的节点 如果不存在,则 节点编目:db2 catalog tcpip ...
- iOS UI高级之网络编程(HTTP协议)
HTTP协议的概念 HTTP协议,Hyper Text Transfer Protocol (超文本传输协议)是用于从万维网服务器传送超文本到本地浏览器的传输协议,HTTP是一个应用层协议,由请求和响 ...
- thinkphp用phpexcel读取excel,并修改列中的值,再导出excel,带往excel里写入图片
<?php class GetpriceAction extends AdministratorAction { // 文件保存路径 protected $savepath; // 允许上传的文 ...
- Modelsim的demo入门教程
写在前面的话学过MCU设计的朋友都知道,系统调试是多么的重要.而对于FPGA设计来说,仿真确实最重要的.一个完整的项目,必须有完整的仿真平台.有朋友说,按键仿真模型没法搞. 我只能说,你并不了解硬件及 ...
- 硬件相关-ADC原理(未完成)
一.模数转换的一般步骤: 1)采样和保持 为了把模拟信号转换成对应的数字信号,必须首先将模拟量每隔一定时间抽取一次样值,使时间上连续变化的模拟量变为一个时间上断续变化的模拟量,这个过程称为采样. 为了 ...
- transform属性
transform属性 在OC中,通过transform属性可以修改对象的平移.缩放比例和旋转角度常用的创建transform结构体方法分两大类 (1) 创建“基于控件初始位置”的形变 CGAffin ...
- DebugViewHierarchy
DebugViewHierarchy(视图调试)是XCode6新出的一项功能,它可以让开发者在程序运行时,动态的查看当前界面的显示情况,包括视图的层次,控件的大小和位置,而且会以3D效果显示当前视图的 ...
- 转载:Comet:基于 HTTP 长连接的“服务器推”技术
转自:http://www.ibm.com/developerworks/cn/web/wa-lo-comet/ 很多应用譬如监控.即时通信.即时报价系统都需要将后台发生的变化实时传送到客户端而无须客 ...
- Netsharp快速入门(之17) Netsharp基础功能(参照高级设置)
5.2 参照高级设置 1. 以往来字段为例,打开平台工具-界面管理-列表管理,找到往来单位的资源节点,记下列表项目中的名称 2.记下往来单位部件工作区的id 3. 打开平台工具-界面管理-参照 ...