ACDream - Power Sum

先上题目:

Power Sum

Time Limit: 20000/10000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
SubmitStatus

Problem Description

给出n,m,p,求 (1^m + 2^m + 3^m + 4^m + ... + n^m) % p

Input

第一行一个数T( <= 10),表示数据总数 

然后每行给出3个数n,m,p(1 <= n <= m <= 10^18, 1 <= p <= 10^6, p是质数

Output

每组数据输出你求得的结果

Sample Input

2
1 1 11
3 2 11

Sample Output

1
3

Hint

i^m即求 i * i * i * i * i... * i(m个i),比如2^3即2 * 2 * 2 
 
  分析,首先n很大,但是这个求和需要模p,所以我们可以考虑将求和范围压缩在0~p-1中间,然后求出结果以后乘上倍数再加上剩余部分就可以了。但是这样时间复杂度还会是很大。这里还可以用欧拉定理来优化。
  n,a为正整数,且n,a互质,则:    
 
  
  
 
  因为这里我们已经已经将求和范围压缩在0~p-1里面了,同时因为p是一个质数,所以我们知道1~p-1的数都符合上述的公式。对于求次幂,我们可以用快速幂,这样问题就基本解决了。这就是标准解法。问题是我用这种方法结果还是超时了,主要问题好像是取模太多了。
 
  于是我又想出另一种解法对于每一个数都可以分解成素数相乘,那我们先压缩数据在0~p-1之间,然后就可以将这些数分解成质数的幂相乘,然后我们可以想素数筛法那样求一遍,最终就可以得到结果。这种方法之所以可以使用是因为10^6一下的质数大概有1.2*10^5这么多个,不算多,所以可行。同时这种方法相对于前面的方法速度上应该会更快。前一种方法的时间复杂度大概是O(p*logp),后一种方法的时间复杂度大概是O(ploglogp),接近O(p)。
 
 
 
 
 
 
上代码:
 
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define LL long long
 5 #define MAX 1000002
 6 using namespace std;
 7  
 8 LL n,m,p,ti;
 9  
10  
11 bool f[MAX];
12 LL mm[MAX];
13 LL ans,rr,r;
14  
15 LL Fast_Mod(LL i,LL t){
16     LL a = 1;
17     while(t){
18         if(t&1) a = i*a%p;
19         i = (i%p)*(i%p)%p;
20         t>>=1;
21     }
22     return a;
23 }
24  
25 void solve1(){
26     ans=0;
27     memset(f,0,sizeof(f));
28     for(int i=1;i<=p;i++) mm[i]=1;
29     LL u;
30     f[1]=1;
31     for(LL i=1;i<=p;i++){
32         if(!f[i]){
33             mm[i] = Fast_Mod(i,m);
34             for(LL j=i+i;j<=p;j+=i){
35                 f[j]=1;
36                 u = j;
37                 while(u%i==0){
38                     u/=i;
39                     mm[j]=mm[j]*mm[i]%p;
40                 }
41             }
42         }
43         ans = (ans + mm[i])%p;
44         if(i<=r) rr=ans;
45     }
46 }
47  
48 void solve2(){
49     ans=0;
50     memset(f,0,sizeof(f));
51     for(int i=1;i<=r;i++) mm[i]=1;
52     LL u;
53     f[1]=1;
54     for(LL i=1;i<=r;i++){
55         if(!f[i]){
56             mm[i] = Fast_Mod(i,m);
57             for(LL j=i+i;j<=r;j+=i){
58                 f[j]=1;
59                 u = j;
60                 while(u%i==0){
61                     u/=i;
62                     mm[j]=mm[j]*mm[i]%p;
63                 }
64             }
65         }
66         ans = (ans + mm[i])%p;
67     }
68 }
69  
70  
71 int main()
72 {
73     int t;
74     //freopen("data.txt","r",stdin);
75     scanf("%d",&t);
76     while(t--){
77         scanf("%lld %lld %lld",&n,&m,&p);
78         ti = n/p;
79         r = n%p;
80         rr=0;
81         if(ti!=0){
82             solve1();
83             ans = (ans*ti)%p;
84             ans = (ans+rr)%p;
85         }else{
86             solve2();
87         }
88         printf("%lld\n",ans);
89     }
90     return 0;
91 }
Power Sum

 

 
 
 
 
posted @ 2014-07-25 11:46  海拉鲁的林克  阅读(272)  评论(0编辑  收藏  举报