LightOJ - 1054 - Efficient Pseudo Code
先上题目
Time Limit: 1 second(s) | Memory Limit: 32 MB |
Sometimes it's quite useful to write pseudo codes for problems. Actually you can write the necessary steps to solve a particular problem. In this problem you are given a pseudo code to solve a problem and you have to implement the pseudo code efficiently. Simple! Isn't it? :)
pseudo code
{
take two integers n and m
let p = n ^ m (n to the power m)
let sum = summation of all the divisors of p
let result = sum MODULO 1000,000,007
}
Now given n and m you have to find the desired result from the pseudo code. For example if n = 12 and m = 2. Then if we follow the pseudo code, we get
pseudo code
{
take two integers n and m
so, n = 12 and m = 2
let p = n ^ m (n to the power m)
so, p = 144
let sum = summation of all the divisors of p
so, sum = 403, since the divisors of p are 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 36, 48, 72, 144
let result = sum MODULO 1000,000,007
so, result = 403
}
Input
Input starts with an integer T (≤ 5000), denoting the number of test cases.
Each test case will contain two integers, n (1 ≤ n) and m (0 ≤ m). Each of n and m will be fit into a 32 bit signed integer.
Output
For each case of input you have to print the case number and the result according to the pseudo code.
Sample Input |
Output for Sample Input |
3 12 2 12 1 36 2 |
Case 1: 403 Case 2: 28 Case 3: 3751 |
这一题的题意很简单,就是给你2个数n,m求n的m次幂的因子和是多少,当然,结果要模1000000007。这一题的要求其实有两个,一是不超时,二是得到正确的答案,则用普通的pow函数配合求因子明显不行。
首先,因为数字很大,如果先pow在求模明显早溢出了,其次,太大的数字求因子和明显慢得像蜗牛。所以这一题需要自己写一个快速幂,同时要知道一件事就是我们不需要一开始就算出pow(n,m)出来,由素数唯一分解定理可以得到,pow(n,m)的分解出来的素数种类和n分解出来的种类是一样的只是数目上是n的各个素数的数目的m倍,所以我们可以先求出n的素数,然后每一个的含有数目都乘上m即可,然后就是求因子和了。求因子和需要求每一个素数的p^αi这一个等比数列,然后根据乘法原理求出结果,就是因子和这里可以很好地理解,每一个素数出现有0~p^αi这么多种状态,它们和其他素数的不同状态组合起来就得到所有的结果了。这里有很多方法,师兄的代码是用逆元来解,但是暂时我还不懂逆元怎样用,而且师兄说过这种方法有局限,因此这里我使用的是另一种解法,就是二分求等比数列。分析如下图
代码可以对两种情况进行完全分开的写求值过程,而不是偶数时前半部分化为奇数情况调用,前者大概会快一点。(= =反正两种我都试过了)
上代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #define MOD 1000000007 5 #define LL long long 6 #define MAX (1<<16)+10 7 using namespace std; 8 9 LL pri[MAX]; 10 int tot; 11 bool mark[MAX]; 12 13 void dedeal() 14 { 15 LL i,n,j; 16 n=MAX-10; 17 memset(pri,0,sizeof(pri)); 18 memset(mark,0,sizeof(mark)); 19 for(i=2;i<=n;i++) 20 { 21 if(!mark[i]) 22 { 23 pri[tot++]=i; 24 for(j=i*i;j<=n;j+=i) 25 { 26 mark[j]=1; 27 } 28 } 29 } 30 } 31 32 LL FastMod(LL a,LL q) 33 { 34 if(q==0) return 1; 35 LL t=FastMod(a,q>>1); 36 t=t%MOD; 37 t=t*t%MOD; 38 if(q&1) t=t*a%MOD; 39 return t; 40 } 41 42 /* 43 LL FastMod(LL a,LL q) 44 { 45 LL k,r; 46 if(!q) return 1; 47 k=1; 48 r=a%MOD; 49 while(q>1) 50 { 51 if(q&1) k=k*r%MOD; 52 r=r*r%MOD; 53 q>>=1; 54 } 55 return r*k%MOD; 56 } 57 */ 58 LL f(LL a,LL q) 59 { 60 if(q==0) return 1; 61 if(q&1) return (f(a,q>>1)%MOD*(1+FastMod(a,(q+1)>>1)))%MOD; 62 return (f(a,q-1)%MOD+FastMod(a,q))%MOD; 63 } 64 65 LL fs(LL n,LL M) 66 { 67 LL i,m,sum,amo; 68 i=0; 69 m=sqrt(n); 70 sum=1; 71 for(i=0;i<tot && pri[i]<=m;i++) 72 { 73 if(n%pri[i]==0) 74 { 75 amo=0; 76 //printf("%lld ",pri[i]); 77 while(n%pri[i]==0) {n/=pri[i];amo++;} 78 sum=sum*f(pri[i],(amo*M))%MOD; 79 } 80 if(n==1) break; 81 } 82 if(n>1) sum=sum*f(n,M)%MOD; 83 return sum%MOD; 84 } 85 86 int main() 87 { 88 int t,i; 89 LL n,m,sum; 90 //freopen("data.txt","r",stdin); 91 dedeal(); 92 scanf("%d",&t); 93 for(i=1;i<=t;i++) 94 { 95 scanf("%lld %lld",&n,&m); 96 sum=fs(n,m); 97 printf("Case %d: %lld\n",i,sum%MOD); 98 } 99 return 0; 100 }