LightOJ1132---Summing up Powers (矩阵快速幂+二项式定理(简单推理))

【题目来源】https://vjudge.net/problem/LightOJ-1132
【题意】
题意呢,就像题面描述的一样。。。
【思路】
首先,这道题因为存在递推式,并且,N非常之大,所以想到矩阵快速幂,接着,整体思路为(假设前n项和为Sn):
S(n+1)=Sn+(n+1)^k
然后按照一般的步骤(将左边,右边化为后,前两个状态,也即是说,后一状态可由前一状态递推而来),但是呢,遇到了一点阻碍,怎么样才可以将(n+1)^k化为关于n的递推式呢?
进而想到二项式定理:
(a+b)^k=C(0,k)*a^k*b^0+C(1,k)*a^k-1*b^1+…+C(k,k)*a^0*b^k;
而在这里(1的多少次方均为1,乘法不做记录):
(n+1)^k=C(0,k)*n^k+C(1,k)*n^k-1+…+C(k,k)*n^0;
所以这道题化为矩阵快速幂的递推式就出来了:
S(n+1)=Sn+C(0,k)*n^k+C(1,k)*n^k-1+…+C(k,k)*n^0;
写出系数矩阵:
这里写图片描述
【代码】

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL N,mod;
int K;
struct mat
{
    LL a[55][55];
};
LL z_h[55][55];//预处理k的所有可能性的二项式系数
mat operator*(mat s,mat t)
{
    mat r;
    for(int i=1; i<=K+2; i++)
        for(int j=1; j<=K+2; j++)
        {
            r.a[i][j]=0;
            for(int k=1; k<=K+2; k++)
                if(s.a[i][k]&&t.a[k][j])
                {
                    r.a[i][j]+=s.a[i][k]*t.a[k][j]%mod;
                    r.a[i][j]%=mod;
                }
        }

    return r;
}
void init()
{
    mod=1;
    for(int i=1; i<=32; i++)
    {
        mod*=2;
    }
    for(int i=1; i<=50; i++)
    {
        z_h[i][1]=1;
        int x=i;
        for(int j=2; j<=i+1; j++)
        {
            z_h[i][j]=z_h[i][j-1]*x/(j-1);
            x--;
        }
    }
}
mat pow_mat(mat base)
{
    mat ans;
    memset(ans.a,0,sizeof(ans.a));
    for(int i=1; i<=K+2; i++)
    {
        ans.a[i][i]=1;
    }
    N-=1;
    while(N)
    {
        if(N&1)
        {
            ans=ans*base;
        }
        base=base*base;
        N>>=1;
    }
    return ans;

}
int main()
{
    init();
    int T,cases=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%d",&N,&K);
        mat base;
        memset(base.a,0,sizeof(base.a));
        int x=K;
        for(int i=2; i<=K+2; i++)
        {
            int y=1;
            for(int j=i; j<=K+2; j++)
            {
                base.a[i][j]=z_h[x][y++];
            }
            x--;
        }
        base.a[1][1]=1;
        base.a[K+2][K+2]=1;
        for(int i=2; i<=K+2; i++)
        {
            base.a[1][i]=base.a[2][i];
        }
        mat ans=pow_mat(base);
        LL sum=0;
        for(int i=1; i<=K+2; i++)
        {
            sum+=ans.a[1][i]%mod;
            sum%=mod;
        }
        printf("Case %d: %lld\n",cases++,sum);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值