POJ 1845-Sumdiv 数论 +快速幂&&筛素&&分解质因数&&求因数之和的模板

17 篇文章 0 订阅
2 篇文章 0 订阅

poj计划的第一个坎,非常经典的一道题在此记录一下以后总结
知识点:
1 (a+b)%c = (a%c+b%c)%c
(a*b)%c = ((a%c)*(b%c))%c

2 计算a^n 要用快速幂((logn)渣渣我都能迅速打出来)

3 任何数都能分解成几个质因数相乘

4 求一个数的所有因数之和 = (a^0+a^1+a^2+a^3+….a^n) * ( a1^0+a1^1+a1^2+a1^3+….a1^n1)* (a2^0+a2^1+a2^2+a2^3+….a2^n2)…..*(an^0+an^1+an^2+an^3+….an^nn)
其中a,a1,a2,,,,代表它的质因数,n,n1,n2….nn代表它所代表的质因数的个数

5 二分求a^0+a^1+a^2……a^n的结果,二分很抽象新手难以想到现屡一下思路。。。
(1) 先分析n为奇数时a^n/a^(n/2)=a^(n/2+1)/a^0=a^(n/2+2)/a^1=…=a^(n/2+1);
所以 a^0+a^1+a^2……a^n = a^0+a^1+a^2+….a^n/2+a^(n/2+1)( a^0+a^1+a^2+….a^n/2) = (1+a^(n/2+1) (a^0+a^1+a^2+….a^n/2 )
(2)当分析n为偶数时同分析奇数一样都有对应关系,下标0跟n/2+1,1跟n/2+2……n/2-1跟n所代表的a值相除都可以得同一个系数为a^(n/2+1)。但有一组不一样就是a^n/2;
没有系数与它对应所以要另算
所以递推公式为a^0+a^1+a^2……a^n = a^0+a^1+a^2+….a^n/2+a^(n/2+1)( a^0+a^1+a^2+….a^(n/2-1)) = (1+a^(n/2+1) (a^0+a^1+a^2+….a^(n/2-1 ))+a^(n/2);

6 细心该取模的地方别忘写了一下写对不然以后查错很麻烦,同时这种数论题数据很作你是不能想出特殊数据的,要中途wa只能眼睛干瞪差错(写给马虎的渣渣自己)

PS: 我也看题解写的。。。但题解都写得很简单,一股装逼的味道。。。我自己还是要屡一下证明的细节要不就是全抄的了。。另外把这个当以后的模板了很有用的。

//2015.11.20 by blacktea
//筛素数&&分解质因子&&快速幂&&二分求所有因子的和->模板
#include<cstdio>
#include<cstring>
#define mod 9901
int am[10000],x,n,l=0,pri[10000],prix[2000],l1;
__int64 priam[2000];
void toGetPrime()//筛素数
{
    for(int i=2;i<=10000;i++)
    if(!am[i]){
        pri[l] = i;
        l++;
        for(int j=2;j*i<=10000;j++)
          am[i*j] = 1;
    }
}
void toApartPrime()//分解质因子
{
   memset(priam,0,sizeof(priam));
   l1=0;
   for(int i=0;pri[i]*pri[i]<=x;i++)
   {
        if(!(x%pri[i])){
        prix[l1] = pri[i];
          while(x%pri[i]==0)
          {
          x/=pri[i];
          priam[l1]++;
          }
          priam[l1]*=n;
          l1++;
       }
   }
   if(x!=1){prix[l1] = x;priam[l1] = 1;priam[l1]*=n;l1++;}
}
int pow_m(int a,__int64 n)//快速幂
{
    a%=mod;
    int result = 1,pre = a;
    while(n)
    {
       if(n&1)
       {result *= pre;result %= mod;}
       pre*=pre;
       pre%=mod;
       n>>=1;
    }
    return result;
}
int toCalculate(int a,__int64 sum)//二分求所有因子的和
{
   int result = 1;
   if(sum==0)return 1;
   if(sum%2)result = ((1+pow_m(a,sum/2+1))%mod)*toCalculate(a,sum/2);
   else result = ((1+pow_m(a,sum/2+1))%mod)*toCalculate(a,sum/2-1)+pow_m(a,sum/2);
   result%=mod;
   return result;
}
int main()
{
    toGetPrime();
    while(scanf("%d%d",&x,&n)!=EOF)
    {
      int result =1;
      if(x==1){printf("1\n");continue;}
      else if(x==0){printf("0\n");continue;}
      toApartPrime();
      for(int i=0;i<l1;i++)
      {
         result*=toCalculate(prix[i],priam[i]);
         result%=mod;
      }
      printf("%d\n",result);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值