HDU 4059 The Boss on Mars-矩阵+容斥

错了29遍,终成正果。。。。。

根据题意,很容易的可以想到容斥。

然后的问题就是如何求

sum(n)=1^4+2^4+3^4+....+n^4;

有三种道路:

很显然:1^4+2^4+3^4+....+n^4=(n^5)/5+(n^4)/2+(n^3)/3-n/30;

则1,用java的大数去敲这个的代码。

2,用c++敲,但是用到分数取模,求逆元。

3,用c++敲,但是不用这个公式,用矩阵去构造sum(n).

我用的是第三种。但是第三种有的缺陷,就是时间复杂度有点高。

接下来的问题就是如何优化时间复杂度。

可以预处理1~200W的sum,然后剩下的再用矩阵去构造。

具体构造方法看代码。。


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<vector>
using namespace std;
#define LL __int64
#define MOD 1000000007
#define maxn 2000007
LL yu[maxn];
struct matrix
{
    LL mat[7][7];
    matrix()
    {
        memset(mat,0,sizeof(mat));
    }
    friend matrix operator *(matrix A,matrix B)
    {
        int i,j,k;
        matrix C;
        for(i=1; i<=6; i++)
        {
            for(j=1; j<=6; j++)
            {
                for(k=1; k<=6; k++)
                {
                    C.mat[i][j]=(C.mat[i][j]+(A.mat[i][k]*B.mat[k][j])%MOD)%MOD;
                }
                C.mat[i][j]=C.mat[i][j]%MOD;
            }
        }
        return C;
    }
} ONE,AA[30];
matrix powmul(matrix A,LL k)
{
    matrix B;
    for(int i=1; i<=6; i++)B.mat[i][i]=1;
    int l=1;
    while(k)
    {
        if(k&1)B=B*AA[l];
        l++;
        k>>=1;
    }
    return B;
}
vector<int>vec;
void init()
{
    int i,j;
    //构造矩阵
    ONE.mat[1][1]=1;ONE.mat[1][2]=1;ONE.mat[1][3]=4;
    ONE.mat[1][4]=6;ONE.mat[1][5]=4;ONE.mat[1][6]=1;
    ONE.mat[2][1]=0;ONE.mat[2][2]=1;ONE.mat[2][3]=4;
    ONE.mat[2][4]=6;ONE.mat[2][5]=4;ONE.mat[2][6]=1;
    ONE.mat[3][1]=0;ONE.mat[3][2]=0;ONE.mat[3][3]=1;
    ONE.mat[3][4]=3;ONE.mat[3][5]=3;ONE.mat[3][6]=1;
    ONE.mat[4][4]=1;ONE.mat[4][5]=2;ONE.mat[4][6]=1;
    ONE.mat[5][4]=0;ONE.mat[5][5]=1;ONE.mat[5][6]=1;
    ONE.mat[6][6]=1;
    yu[0]=0;
    yu[1]=1;
    LL x;
    for(i=2;i<maxn;i++)//预处理1~200W的sum[x]
    {
        x=i%MOD;
        x=x*i;
        x=x%MOD;
        x=x*i;
        x=x%MOD;
        x=x*i;
        x=x%MOD;
        yu[i]=yu[i-1]+x;
        yu[i]=yu[i]%MOD;
    }
    AA[1]=ONE;
    for(i=2;i<30;i++)AA[i]=AA[i-1]*AA[i-1];
}

matrix A;
LL kan(LL x)//求sum[x]
{
    if(x<maxn)return yu[x];
    matrix OP;
    for(int i=1;i<=6;i++)OP.mat[i][1]=1;
    A=powmul(ONE,x-1);
    OP=A*OP;
    return OP.mat[1][1];
}
LL pan(LL n,LL x)
{
    if(x>=n)return 0;
    LL p=1;
    LL ns=4;
    while(ns--)
    {
        p=p*x;
        p=p%MOD;
    }
    ns=(n-1)/x;
    p=p*kan(ns);
    p=p%MOD;
    return p;
}
void dos(LL n)
{
    LL p=1;
    LL ans=0;
    int i,j,leap;
    LL m=n;
    vec.clear();
    for(i=2;i*i<=n;i++)//求因子的过程
    {
        if(n%i==0)
        {
            vec.push_back(i);
        }
        while(n%i==0)n=n/i;
    }
    if(n!=1)vec.push_back(n);
    n=m;
    int t=1<<(vec.size());
    for(i=1;i<t;i++)//容斥的过程
    {
        leap=0;
        p=1;
        for(j=0;j<vec.size();j++)
        {
            if(i&(1<<j))
            {
                leap++;
                p=p*vec[j];
            }
        }
        leap=leap%2;
        if(leap)ans+=pan(n,p);
        else ans-=pan(n,p);
        ans=(ans+MOD)%MOD;
    }
    ans=kan(n-1)-ans;
    ans=(ans+MOD)%MOD;
    printf("%I64d\n",ans);
}
int main()
{
    int T;
    LL n;
    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d",&n);
        if(n==1)
        {
            cout<<"0"<<endl;
            continue;
        }
        dos(n);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值