zoukankan      html  css  js  c++  java
  • ACDream

    先上题目:

    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
    ",ans);
    89     }
    90     return 0;
    91 }
    Power Sum
     
     
     
     
  • 相关阅读:
    【转】依赖注入那些事儿
    【转】Visual Studio單元測試小應用-測執行時間
    【转】 代码设计敏捷开发三部曲
    【转】 c#中两个DateTimePicker,一个时间设置为0:0:0,另一个设置为23:59:59
    【转】 C#获取当前程序运行路径的方法集合
    CSVHelper读出乱码 解决方案
    CvsHelper 使用指南
    【转】 C# ListView实例:文件图标显示
    【转】C# winform 加载网页 模拟键盘输入自动接入访问网络
    基于MHA的MySQL高可用
  • 原文地址:https://www.cnblogs.com/sineatos/p/3867613.html
Copyright © 2011-2022 走看看