【 HDU 4059 The Boss on Mars】 差分序列+容斥

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4059

题目大意:给你一个整数n,让你求前面n个数中与n互素的数E(x^4)的和。

解题思路:

    可以先求出Sum(n):表示1^4+2^4+3^4+……+n^4;

    然后再求Sum(n)-E(x^4)  ,x表示与 n不互素的数。

   求与n不互素的数可以利用容斥定理,求Sum(n)可以利用差分。

简单介绍一下差分序列:

给你一列数 a[i][1],a[i][2],a[i][3],a[i][4],a[i][5]……

那么a[i][j]=a[i-1][j+1]-a[i-1][j], 即后一行是上一行相邻两项的差(第一行除外)。

如果给你一个多项式, 比如 f(x)=(x+1)*(x+2)*……*(x+p),即多项式最高项系数为p。

则这个差分表有如下性质:

1、将 0、1、2、……、p-1、p分别代入多项式中,则他们组成多项式的第一行,后面的差分表可以由上一行推出。第p+1行以后差分表的值都为0。

2、我们这里要用的差分序列是他的第0行对角线的数。 我们设他们为c0、c1、c2、……cp;

   ==>  第n项的值:f(n)=c0*C(n,0)+c1*C(n,1)+c2*C(n,2)+……+cp*(n,p);

  ==>  前n项的值:Sum(n)=c0*C(n+1,1)+c1*C(n+1,2)+c2*C(n+1,3)+……+cp*(n+1,p+1);

 

  这题藐视搞得我蛋疼,我是把求前n项和组合公式给化简出来(Sum(n)=(n^5)/5+(n^4)/2+(n^3)/3-n/30,最后发现求逆元取模的时候问题很多。最后又多写了几个函数,直接求组合数的值,分母和模求逆元的时候打表先求好。

 还有要注意的是:

1、这题不打表先求素数会超时。

2、运用容斥定理的时候取模遇减号要加mod,还有容斥定理求出的数可以用到Sum(n):比如2^4+4^4+6^4+8^4 = 2^4*(1^4+2^4+3^4+4^4) 看懂了木有。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<vector>
  6 #define lld long long
  7 #define MOD 1000000007
  8 using namespace std;
  9 int prime[10000],cnt=0,flag[10005]= {0};
 10 vector<int>vt;
 11 
 12 lld ext_gcd(lld a, lld b, lld &x, lld &y)
 13 {
 14     if( !b ) return x=1,y=0,a;
 15     lld d= ext_gcd(b, a%b, y, x);
 16     y-= a/b*x;
 17     return d;
 18 }
 19 lld Inv(int a, int m)   ///求逆元
 20 {
 21     lld d,x,y;
 22     d= ext_gcd(a, m, x, y);
 23     return x<0 ? x+m : x;
 24 }
 25 
 26 lld base[8]= {0,0,1,14,36,24}; ///差分表第0行对角线的值
 27 lld dd[10]= {0, 1, 500000004, 166666668, 41666667, 808333339}; ///打表求出需要的逆元
 28 
 29 lld Comb(lld n, lld k)   ///组合
 30 {
 31     if(k==n) return 1;
 32     if(k>n) return 0;
 33     lld s= 1;
 34     for(lld i=n,j=1; j<=k; --i,++j)
 35         s= s*i%MOD;
 36     return s*dd[k]%MOD;
 37 }
 38 
 39 lld Sum(lld n)    ///求n^4的前n项和
 40 {
 41     if(n==1) return 1;
 42     lld sum= 0;
 43     for(int i=2; i<=5; ++i)    ///差分
 44     {
 45         sum+= ( Comb( n+1, i ) * base[i] )%MOD;
 46         if( sum>=MOD ) sum-= MOD;
 47     }
 48     return sum;
 49 }
 50 
 51 lld Pow(lld n)  ///求n^4
 52 {
 53     lld ans=n;
 54     ans=(((((ans*n)%MOD)*n)%MOD)*n)%MOD;
 55     return ans;
 56 }
 57 
 58 void Prime()   ///筛选素数,便于后面的分解
 59 {
 60     for(int i=2; i<=10000; i++)
 61     {
 62         if(flag[i]) continue;
 63         prime[cnt++]=i;
 64         for(int j=2; j*i<=10000; j++)
 65             flag[i*j]=1;
 66     }
 67 }
 68 
 69 lld dfs(int idx,lld n)     ///容斥原理
 70 {
 71     lld ret=0,tmp;
 72     for(int i=idx; i<vt.size(); i++)
 73     {
 74         tmp=vt[i];
 75         ret=(ret+(Sum(n/tmp)*Pow(tmp))%MOD)%MOD;
 76         ret=((ret-dfs(i+1,n/tmp)*Pow(tmp))%MOD+MOD)%MOD;
 77     }
 78     return ret%MOD;
 79 }
 80 int main()
 81 {
 82     int t;
 83     lld n;
 84     Prime();
 85     scanf("%d",&t);
 86     while(t--)
 87     {
 88         scanf("%I64d",&n);
 89         vt.clear();
 90         lld tmp=n;
 91         for(int i=0; i<cnt&&prime[i]<=tmp; i++)  ///求n的素因子
 92             if(tmp%prime[i]==0)
 93             {
 94                 vt.push_back(prime[i]);
 95                 while(tmp%prime[i]==0)
 96                     tmp/=prime[i];
 97             }
 98         if(tmp!=1)
 99             vt.push_back(tmp);
100 
101         lld sum=((Sum(n)-dfs(0,n))%MOD+MOD)%MOD;
102         printf("%I64d\n",sum);
103     }
104     return 0;
105 }

 

 

 

  

posted @ 2012-12-25 23:54  Mr. Ant  阅读(673)  评论(0编辑  收藏  举报