题目大意就是给定a和b,求a^b的约数和

f(n) = sigma(d) [d|n] 

这个学过莫比乌斯反演之后很容易看出这是一个积性函数

那么f(a*b) = f(a)*f(b)  (gcd(a,b)=1)

那么这道题就可以将a分解为每一个素数的k次方,求出相对应的f(p^k),将每一个乘在一起就行了

因为每一个素数得到的都是只有唯一的素数因子,那么f(n) 又变成了求 a^0+a^1+a^2....+a^k的值了 (n=a^k)

这里因为要取模,所以我用的是矩阵快速幂求的,网上别人用的都是二分分治求等比数列,反正这两种方法都不需要逆元,都能过

但我最开始写的要逆元的方法过不了也不知道为什么,希望路过大神知道的提个醒

矩阵快速幂的矩阵构造两维,第一维是等比关系,第二维保存前面所有值的和 

{

a , a

0 , 1

}

 

分治求等比数列的和:

3: 用递归二分求等比数列1+pi+pi^2+pi^3+...+pi^n:

(1)若n为奇数,一共有偶数项,则:
      1 + p + p^2 + p^3 +...+ p^n

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2) * (1+p^(n/2+1))
      = (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))

上式红色加粗的前半部分恰好就是原式的一半,那么只需要不断递归二分求和就可以了,后半部分为幂次式,将在下面第4点讲述计算方法。

 

(2)若n为偶数,一共有奇数项,则:
      1 + p + p^2 + p^3 +...+ p^n

      = (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2-1) * (1+p^(n/2+1)) + p^(n/2)
      = (1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2);

   上式红色加粗的前半部分恰好就是原式的一半,依然递归求解

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 #define ll long long
 7 const int MOD = 9901;
 8 
 9 struct Matrix{
10     int m[2][2];
11     void init(){memset(m , 0 , sizeof(m)); m[0][0] = m[1][1] = 1;}
12     Matrix operator*(const Matrix &p)const {
13         Matrix ans ;
14         for(int i=0 ; i<2 ; i++)
15             for(int j=0 ; j<2 ; j++){
16                 ans.m[i][j] = 0;
17                 for(int k=0 ; k<2 ; k++)
18                     ans.m[i][j] = (ans.m[i][j]+m[i][k]*p.m[k][j]%MOD)%MOD;
19             }
20         return ans;
21     }
22     void out(){
23         cout<<m[0][0]<<" "<<m[0][1]<<endl<<m[1][0]<<" "<<m[1][1]<<endl;
24     }
25 };
26 
27 Matrix q_pow(Matrix a , int b)
28 {
29     Matrix ans;
30     ans.init();
31     while(b){
32         if(b&1) ans = ans*a;
33         a = a*a ; b>>=1;
34     }
35     return ans;
36 }
37 
38 int get(int a , int b)
39 {
40     //a^0+a^1+a^2...+a^b
41     Matrix p;
42     p.m[0][0] = a%MOD , p.m[0][1] = a%MOD , p.m[1][0] = 0 , p.m[1][1] = 1;
43     p = q_pow(p , b);
44     return (p.m[0][1]+p.m[1][1])%MOD;
45 }
46 
47 void fenjie(int a , int b)
48 {
49     int mx = (int)sqrt(a+0.5) , ret = 1;
50     for(int i=2 ; i<=mx ; i++){
51         if(i>a) break;
52         int cnt = 0;
53         while(a%i==0){
54             cnt+=b , a/=i;
55         }
56         if(cnt) ret = (ret*get(i , cnt))%MOD;
57     }
58     if(a>1) ret = (ret*get(a , b))%MOD;
59     printf("%d\n" , ret);
60 }
61 
62 int main() {
63    // freopen("a.in" , "r" , stdin);
64    // freopen("compare.txt" , "w" , stdout);
65     int a , b;
66     while(~scanf("%d%d" , &a , &b)){
67         if(a == 0) puts("0");
68         else fenjie(a , b);
69     }
70     return 0;
71 }
矩阵快速幂
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define ll long long
const int MOD = 9901;

int q_pow(int a , int b)
{
    a = a%MOD;
    int ret = 1;
    while(b){
        if(b&1) ret = ret*a%MOD;
        a = a*a%MOD ; b>>=1;
    }
    return ret;
}

int inv(int a){return q_pow(a , MOD-2);}

int sum(int a , int b)
{
    //a^0+a^1+a^2...+a^b
    if(b==0) return 1;
    if(a==0) return 0;
    if(b&1) return ((1+q_pow(a , b/2+1))%MOD*(sum(a , b/2)%MOD))%MOD;
    else return ((1+q_pow(a , b/2+1))%MOD*(sum(a , b/2-1)%MOD)%MOD+(q_pow(a , b/2)%MOD))%MOD;
}

void fenjie(int a , int b)
{
    int mx = (int)sqrt(a+0.5) , ret = 1;
    for(int i=2 ; i<=mx ; i++){
        if(i>a) break;
        int cnt = 0;
        while(a%i==0){
            cnt+=b , a/=i;
        }
        if(cnt) ret = (ret*sum(i , cnt))%MOD;
    }
    if(a>1) ret = (ret*sum(a , b))%MOD;
    printf("%d\n" , ret);
}

int main() {
   // freopen("a.in" , "r" , stdin);
   // freopen("compare.txt" , "w" , stdout);
    int a , b;
    while(~scanf("%d%d" , &a , &b)){
        if(a == 0) puts("0");
        else fenjie(a , b);
    }
    return 0;
}
分治

 

 posted on 2015-09-10 16:12  Love风吟  阅读(221)  评论(0编辑  收藏  举报