数论(容斥原理)hdu-4509-The Boss on Mars

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4059

题目大意:

给一个n,求1~n中与n互质的数的4次方的总和。

解题思路:

容斥原理、逆元、公式。

其实是蛮简单的一道题。囧囧。

首先必须知道1^4+2^4+...+n^4=n*(n+1)*(2n+1)(3n^2+3n-1)/30. 除以30可以转化成乘以30的逆元,30^(M-2) 由费马小定理很快可以得到。

先求出1^4+2^4+...+n^4然后减去与n不互质的。  假设n=p1^a1*p2^a2...pn^an  用容斥原理先减去含一个质因数的所有的不超过n的倍数,然后加上含两个质因数的,然后减去含三个质因数的。一个dfs就可以搞定。

代码:

 

#include<iostream>

#include<cmath>

#include<cstdio>

#include<cstdlib>

#include<string>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<set>

#include<stack>

#include<list>

#include<queue>

#define eps 1e-6

#define INF 0x1f1f1f1f

#define PI acos(-1.0)

#define ll __int64

#define lson l,m,(rt<<1)

#define rson m+1,r,(rt<<1)|1

#pragma comment(linker, "/STACK:1024000000,1024000000")

#define M 1000000007

using namespace std;





//freopen("data.in","r",stdin);

//freopen("data.out","w",stdout);



ll pp[10]; //10个就够了

ll cnt,n,sum,mm;



ll quick(ll a,ll b) //快速幂求 a^b mod M  求30的逆元

{

   ll res=1;

   while(b)

   {

      if(b&1)

         res=(res*a)%M;

      a=(a*a)%M;

      b>>=1;

   }

   return res;

}

ll Four(ll k) //1^4+2^4+...+n^4

{

   return ((((k*(k+1))%M*(2*k+1))%M*((3*k*k%M+3*k-1)%M))%M*mm)%M;

}

void Cal(ll a,ll flag) //求出含有质因数乘积为a的所有的小于n的倍数

{

   ll k=n/a; //a^4+(2a)^4+(3a)^4+...(k*a)^4=a^4*(1^4+2^4+...+k^4)

   ll res=1;

   for(int i=1;i<=4;i++) //求出a的四次方

      res=(res*a)%M;

   res=(res*Four(k))%M; //求出1~k的四次方和



   if(flag&1) //容斥原理

      sum=((sum-res)%M+M)%M;

   else

      sum=(sum+res)%M;

}



void dfs(ll la,ll pos,ll num) //la表示前面的质因数的乘积,pos表示当前的质因数编号,num表示加还是减

{

   if(pos>cnt)

      return ;

   for(int i=pos;i<=cnt;i++)

   {

      Cal(la*pp[i],num); //

      dfs(la*pp[i],i+1,num+1);

   }

}

int main()

{

   int t;



   scanf("%d",&t);

   mm=quick(30,M-2);  //先求一下逆元



   while(t--)

   {

      scanf("%I64d",&n);

      cnt=0;

      ll nn=n;

      sum=Four(n); //求出总的

      for(int i=2;i*i<=nn;i++) //分解质因数 √n的时间复杂度

      {

         if(nn%i==0)

         {

            pp[++cnt]=i;

            while(nn%i==0)

               nn/=i;

         }

      }

      if(nn!=1)

         pp[++cnt]=nn;

      dfs(1,1,1);

      printf("%I64d\n",sum);

   }

   return 0;

}




 


 

你可能感兴趣的:(HDU)