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 二分法思想 ...
随机推荐
- angularjs2 学习笔记(三) 服务
在anglar2中服务是什么? 如果在项目中有一段代码是很多组件都要使用的,那么最好的方式就是把它做成服务. 服务是一种在组件中共享功能的机制,当我们使用标签将多个组件组合在一起时我们需要操作一些数据 ...
- 006--VS2013 C++ 加载其他格式图片,并显示半透明化
//--------------------------------------------MyPaint() 函数------------------------------------------ ...
- C++ this指针详解
C++this指针操作 在这里总结一下this 指针的相关知识点. 首先,我们都知道类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的),那么成员 ...
- 如何写一个漂亮的Liferay Theme 6.2
只要你看到的.想做出来的页面,都可以通过liferay theme来实现,至于具体实现凡方式,那就见仁见智了. 下面,我将介绍如何快速地建一个简单漂亮的liferay theme. 工具:lifera ...
- 二、freemarker.controller半自动静态化+Tomcat虚拟资源映射
描述:本内容主要是讲2个tomcat之间同时共享一个静态话页面,统一入口是springMVC的一个controller,静态化的更新只需要传false.true.把完成的web项目放入a.b服务器To ...
- The income statement
The income statement measures performance over some period of time,usually a quarter or a year.The ...
- Oracle窗口函数显示想要的行数
Oracle中支持窗口函数ROW_NUMBER(),其用法和 MSSQLServer2005中相同,比如我们 执行下面的 SQL语句: SELECT * FROM ( SELECT ROW_NUMBE ...
- ubuntu mysql 使用
环境:ubuntu 12.04.5 mysql-server-5.5 安装:sudo apt-get install mysql-server-5.5 (服务端 第一台虚拟机) sudo apt ...
- 【转载】Oracle实例和Oracle数据库(Oracle体系结构)
免责声明: 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除. 原文作者:Leshami 原文地址:http://blog.csdn.net/ ...
- JS-中对表单处理
一.表单的基本介绍 1. HTML 中,表单是由<form>元素来表示的,而在 JavaScript 中,表单对应的则是HTMLFormElement 类型. HTMLFormElemen ...