hdu1845(a^b的因子和%p)

题目链接:http://poj.org/problem?id=1845

思路:

1.整数唯一分解定理:

任意正整数都有且只有一种方式写出其素因子的乘积表达式。

a=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数

2.约数和公式:

  对于已经分解的整数a=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)

  有a的所有因子之和为

 S` = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)

那么 a^b 的所有因子和为

  S = (1+p1+p1^2+p1^3+...p1^(k1*b)) * (1+p2+p2^2+p2^3+….p2^(k2*b)) * (1+p3+ p3^3+…+ p3^(k3*b)) * .... * (1+pn+pn^2+pn^3+...pn^(kn*b))

对于数列 1, p, p^2, p^3 ...  p^n % mod,其中  mod 为质数,打个表可以发现该数列是一个循环数列,其中存在一个循环节为 1, p, p^1, ... p^(mod-2).其实这点在费马小定理中是有体现的,a^(mod-1) = 1 (% mod).

那么对于求 cnt = 1 + p + p^2 + ... + p^n % mod,可以令

  cc1 = (n + 1) / (mod - 1)

  cc2 = (n + 1) % (mod - 1)

  cnt1 = 1 + p + p^2 + ... + p^(mod - 2)

  cnt2 = 1 + p + p^2 + ... + p^(cc2 - 1)

那么 cnt = cc1 * cnt1 + cnt2 % mod

对于求 a^b,可以先将 a 质因分解,得到 S 的表达式,对于 S 表达式,只需要按照上面的方法求出其中每个乘数项即可.时间复杂度为 O(loga * mod), 本题中 mod = 9901, 时间上是允许的.

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <map>
 4 #define ll long long
 5 using namespace std;
 6
 7 const int mod = 9901;
 8 const int MAXN = 1e5 + 10;
 9 ll prime[MAXN], indx = 0;
10 map<int, int> num;
11
12 int get(ll a, ll b){//计算sigma(a^i),其中0<=i<=b
13     ll sol1 = 0, sol2 = -1, cnt = 1;
14     ll cc1 = (b + 1) / (mod - 1);
15     ll cc2 = (b + 1) % (mod - 1);
16     for(int i = 0; i < mod - 1; i++){
17         sol1 = (sol1 + cnt) % mod;
18         if(sol2 == -1 && i + 1 == cc2) sol2 = sol1;
19         cnt = (cnt * a) % mod;
20     }
21     return (sol1 * cc1 % mod + sol2) % mod;
22 }
23
24 int main(void){
25     ll a, b, sol = 1;
26     cin >> a >> b;
27     for(int i = 2; i * i <= a; i++){
28         if(a % i == 0){
29             prime[indx] = i;
30             while(a % i == 0){
31                 num[i]++;
32                 a /= i;
33             }
34             indx++;
35         }
36     }
37     if(a > 1) prime[indx++] = a, num[a]++;
38     for(int i = 0; i < indx; i++){
39         sol = (sol * get(prime[i], b * num[prime[i]])) % mod;
40     }
41     cout << sol << endl;
42     return 0;
43 }

但是当 mod 比较大时这个方法就不行了,mod 比较大时可以用下面这个代码,贴的 Kuangbin 模板

代码:

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <string.h>
 6 #define ll long long
 7 using namespace std;
 8
 9 //******************************************
10 //素数筛选和合数分解
11 const int MOD = 9901;
12 const int MAXN=10000;
13 int prime[MAXN+1];
14
15 void getPrime(void){
16     memset(prime, 0, sizeof(prime));
17     for(int i = 2; i <= MAXN; i++)
18     {
19         if(!prime[i]) prime[++prime[0]] = i;
20         for(int j=1; j<= prime[0]&&prime[j] <= MAXN/i; j++)
21         {
22             prime[prime[j]*i] = 1;
23             if(i % prime[j] == 0) break;
24         }
25     }
26 }
27
28 ll factor[100][2];
29 int fatCnt;
30
31 int getFactors(ll x){
32     fatCnt = 0;
33     ll tmp = x;
34     for(int i=1; prime[i] <= tmp/prime[i]; i++){
35         factor[fatCnt][1] = 0;
36         if(tmp % prime[i] == 0){
37             factor[fatCnt][0] = prime[i];
38             while(tmp % prime[i] == 0){
39                 factor[fatCnt][1]++;
40                 tmp /= prime[i];
41             }
42             fatCnt++;
43         }
44     }
45     if(tmp!=1)
46     {
47         factor[fatCnt][0]=tmp;
48         factor[fatCnt++][1]=1;
49     }
50     return fatCnt;
51 }
52
53 //******************************************
54 ll pow_m(ll a, ll n)//快速模幂运算
55 {
56     ll res = 1;
57     ll tmp = a % MOD;
58     while(n){
59         if(n & 1){
60             res *= tmp;
61             res%=MOD;
62         }
63         n >>= 1;
64         tmp *= tmp;
65         tmp %= MOD;
66     }
67     return res;
68 }
69
70 ll sum(ll p, ll n){//计算1+p+p^2+...+p^n
71     if(p == 0)return 0;
72     if(n == 0)return 1;
73     if(n & 1){//奇数
74         return ((1 + pow_m(p, n/2 + 1)) % MOD * sum(p, n / 2) % MOD) % MOD;
75     }else return ((1 + pow_m(p, n / 2 + 1)) % MOD * sum(p, n / 2 - 1) + pow_m(p, n / 2) % MOD) % MOD;
76
77 }
78
79 int main(void){
80     int A, B;
81     getPrime();
82     while(scanf("%d%d", &A, &B) != EOF){
83         getFactors(A);
84         ll ans = 1;
85         for(int i = 0; i < fatCnt; i++){
86             ans *= (sum(factor[i][0], B * factor[i][1]) % MOD);
87             ans %= MOD;
88         }
89         printf("%lld\n",ans);
90     }
91     return 0;
92 }

时间: 2024-11-14 12:54:03

hdu1845(a^b的因子和%p)的相关文章

王子和公主 UVa10635

[题目描述]:王子和公主 一个王子和公主在n*n的格子中行走,这些格子是有1....n^2的编号的.现在给定p+1个数,再给定q+1个数,公主和王子可以选择其中某些格子行走,求他们最多能走几个相同的格子. [算法分析]: 这道题读题是关键,然后我们发现需要的是公共的格子,又需要是这个步数最大化,可以想到最长公共子序列的模型.序列长度小于等于62500,最长公共子序列复杂度是n^2,超时.然而可以巧妙的将LCS转化为LIS,使用nlogn的方法求解 解题思路:本题是一道经典的题目,巧妙的将LCS问

hdu 1215(因子和)

七夕节 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 40119    Accepted Submission(s): 12613 Problem Description 七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们的另一半是谁吗?那就按照告示上的方法去找吧!"人们纷纷来到告示

求因子个数和因子和

//求因子个数 int Facnt(int n) { int res = 1; for(int i=2;i*i<=n;i++) { if(n%i == 0) { int cnt = 0; do { n /= i; cnt++; }while(n%i==0); res *= (cnt+1); } } if(n > 1) res = 2*res; return res; } //求因子和 int Facsum(int n) { int res = 1; for(int i=2;i*i<=n;

hdu1215七夕节 筛选法求公因子和

hdu1215七夕节 数据量比较大,筛选法求公因子和即可. #include <iostream> #include<cstdio> #include<string.h> #define maxn 500005 using namespace std; int ans[maxn]; int main() { int cas; int n; cin >> cas; memset(ans,0,sizeof(ans)); for(int i = 1;i <

因子和

因子和 Accepted : 47   Submit : 289 Time Limit : 4000 MS   Memory Limit : 65536 KB 题目描述 如果b能整除a,我们称b为a的因子.现在假设n的所有因子和为f(n): 给你两个整数a,b,(0 ≤ a ≤ b ≤ 5000000): 请你求出所有满足a ≤ i ≤ b的f(i)的和: 例如a=1,b=6,那么你就需要计算f(1)+f(2)+f(3)+f(4)+f(5)+f(6). 我们规定f(0)=0; 输入 不超过200

nylg 小M的因子和

小M的因子和 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 小M在上课时有些得意忘形,老师想出道题目难住他.小M听说是求因子和,还是非常得意,但是看完题目是求A的B次方的因子和,有些手足无措了,你能解决这个问题吗? 输入 有多组测试样例每行两个数 A ,B ,(1≤A,B≤10^9)  输出 输出A的B次方的因子和,并对9901取余. 样例输入 2 3 样例输出 15 上传者 Sumdiv Time Limit: 1000MS   Memory Limit: 30

分治算法求解序列最大子和问题

特别的,当序列所有整数均为负整数时,其最大子和为0. 1 #include <stdio.h> 2 3 int caluMaxSubSum(int *array, int left, int right); 4 5 int main() 6 { 7 int array[6] = {2, -2, 3, 1, -4, 2}; 8 int len_array = sizeof(array)/sizeof(array[0]); 9 int i = 0; 10 int subsum = caluMaxS

Laplace算子和Laplacian矩阵

1 Laplace算子的物理意义 Laplace算子的定义为梯度的散度. 在Cartesian坐标系下也可表示为: 或者,它是Hessian矩阵的迹: 以热传导方程为例,因为热流与温度的梯度成正比,那么温度的梯度的散度就是热量的损失率. 由此可见,Laplace算子可用于表现由于物质分布不均引起的物质输送. 2 Laplace算子的数学意义 现在,在一维空间中简单分析上面的式子: 也可以写作: 把分子第一项和第二项分别按泰勒展开: 可以看出Laplace算子实际上是一个使函数取平均的算子.多维空

NYOJ 767 因子和

因子和 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 题目很简单明了,给你一个数n,判断它是不是素数,如果是素数就输出"Yes",如果不是素数则输出"No"和它的因子和.例如5,输出"Yes",6,输出"No  12".(不包括引号) 输入 共有t组测试数据(1<=t<=100000). 接下来有t行,每行有一个数n(1<n<=2000000). 输出 如果是素数,输出&