zoukankan      html  css  js  c++  java
  • poj1845 Sumdiv 题解报告

    题目传送门

    【题目大意】

    求$A^B$的所有约数之和($mod 9901$)

    【思路分析】

     把$A$分解质因数,则$$A=p_1^{c_1}*p_2^{c_2}*…*p_n^{c_n}$$

    于是可以得到

    $$A^B=p_1^{B*c_1}*p_2^{B*c_2}*…*p_n^{B*c_n}$$

    于是$A^B$的所有约数之和就是

    $$(1+p_1+…+p_1^{B*c_1})*…*(1+p_n+…+p_n^{B*c_n})$$

    上式的每个括号中都是等比数列,如果用求和公式,需要做除法,而$mod$运算的分配律并不适用于除法,所以我们要考虑转化。

    1.递归(分治法)

    把问题分成规模更小的同类子问题,然后递归求解

    设$sum(p,c)=1+p+p^2+…+p^c$

    若$c$为奇数,则

    $$sum(p,c)=(1+p+…+p^{frac{c-1}{2}})+(p^{frac{c+1}{2}}+…+p^c)$$

    $$=(1+p+…+p^{frac{c-1}{2}})+p^{frac{c+1}{2}}*(1+p+…+p^{frac{c-1}{2}})$$

    $$=(1+p^{frac{c+1}{2}})*sum(p,frac{c-1}{2})$$

    若$c$为偶数,则

    $$sum(p,c)=(1+p^{frac{c}{2}})*sum(p,frac{c}{2}-1)+p^c$$

    2.逆元法

    关于乘法逆元的知识详见数论专题学习笔记,这里只放一下代码了。

    【代码实现】

     1 #include<cstdio>
     2 #define rg register
     3 #define go(i,a,b) for(rg int i=a;i<=b;i++)
     4 #define ll long long
     5 using namespace std;
     6 int a,b,m,ans=1;
     7 const int mod=9901;
     8 int p[20],c[20];
     9 void divide(int x){//分解质因数
    10     m=0;
    11     for(rg int i=2;i*i<=x;i++){
    12         if(x%i==0){
    13             p[++m]=i,c[m]=0;
    14             while(x%i==0) x/=i,c[m]++;
    15         }
    16     }
    17     if(x>1) p[++m]=x,c[m]=1;
    18     return;
    19 }
    20 int ksm(int x,ll y){
    21     int as=1;
    22     while(y){
    23         if(y&1) as=(ll)as*x%mod;
    24         x=(ll)x*x%mod;
    25         y>>=1;
    26     }
    27     return as;
    28 }
    29 int main(){
    30     scanf("%d%d",&a,&b);
    31     divide(a);
    32     go(i,1,m){
    33         if((p[i]-1)%mod==0){//特判没有逆元的情况
    34             ans=((ll)b*c[i]+1)%mod*ans%mod;
    35             continue;
    36         }
    37         int x=ksm(p[i],(ll)b*c[i]+1);//分子
    38         x=(x-1+mod)%mod;
    39         int y=p[i]-1;//分母
    40         y=ksm(y,mod-2);//费马小定理求逆元
    41         ans=(ll)ans*x%mod*y%mod;
    42     }
    43     printf("%d
    ",ans);
    44     return 0;
    45 }
    逆元法
     1 #include<cstdio>
     2 #define rg register
     3 #define go(i,a,b) for(rg int i=a;i<=b;i++)
     4 #define ll long long
     5 using namespace std;
     6 int a,b,m,ans=1;
     7 const int mod=9901;
     8 int p[20],c[20];
     9 void divide(int x){//分解质因数
    10     m=0;
    11     for(rg int i=2;i*i<=x;i++){
    12         if(x%i==0){
    13             p[++m]=i,c[m]=0;
    14             while(x%i==0) x/=i,c[m]++;
    15         }
    16     }
    17     if(x>1) p[++m]=x,c[m]=1;
    18     return;
    19 }
    20 int ksm(int x,ll y){
    21     int as=1;
    22     while(y){
    23         if(y&1) as=(ll)as*x%mod;
    24         x=(ll)x*x%mod;
    25         y>>=1;
    26     }
    27     return as;
    28 }
    29 int sum(int x,int y){
    30     if(y==0) return 1;
    31     if(y==1) return x+1;
    32     if(y&1)    return (1+ksm(x,(y+1)/2))*sum(x,(y-1)/2)%mod;
    33     else return (1+ksm(x,y/2))*sum(x,y/2-1)%mod+ksm(x,y)%mod;
    34 }
    35 int main(){
    36     scanf("%d%d",&a,&b);
    37     if(a==0) {printf("0
    ");return 0;}//注意特判
    38     if(b==0) {printf("1
    ");return 0;}
    39     divide(a);
    40     go(i,1,m)
    41         ans=ans*sum(p[i],b*c[i])%mod;
    42     printf("%d
    ",ans);
    43     return 0;
    44 }
    递归法
  • 相关阅读:
    SQL SERVER的检查点checkpoint
    MySQL备份说明
    声明对象和创建对象的区别
    getParameter的用法总结
    Jsp的九大对象,七大动作,三大指令
    为什么内部类访问的外部变量需要使用final修饰
    java synchronized详解
    网上选课系统需求说明书
    第三次作业
    第二次作业
  • 原文地址:https://www.cnblogs.com/THWZF/p/11248143.html
Copyright © 2011-2022 走看看