hdu 3483 矩阵构造

这道题寒假的时候看过,还不小心看了题解,不过题解说神马早就忘了,刚开始解题的时候完全想错了,后来才想起来是用矩阵构造

这道题的确适合构造矩阵,因为所求的函数值满足线性关系,令F(N)为最终求解值

首先我们要明确如果用矩阵的作法,那么矩阵乘法中,最终矩阵,必须包含F(N),还可以包含其他函数g(n),h(n)等等。作为乘数项的矩阵不得与N有关,只能与x有关


F(n+1) = F(n) + x^(n+1)*(n+1)^x
=F(n) + (C(x,0)*n^x + C(x,1)*n^(x-1)+ ... +C(x,x-1)*n+1)*x^(n+1)
=F(n) + (C(x,0)*n^x*(x^n) + C(x,1)*n^(x-1)*(x^n)+ ... +C(x,x-1)*n*(x^n)+1*(x^n))*x
=F(n) + (x*C(x,0)*n^x*(x^n) + x*C(x,1)* n^(x-1)*x^n+...)

很明显,我把x^(n+1)*(n+1)^x 写成了sum{g(i,n)*const(i)},const(i)与n无关,可以乘数项矩阵的一部分),而g(i,n)可以作为最终矩阵的一部分

更重要的是,g(i,n)要和f(n)放在一起构成最终矩阵,也就是g(i,n)如何表达?

g(i+1,n) =(i+1)^x*(x^n) = (C(i,0)*i^x + C(i,1)*i^(x-1) + ..+C(i,i)*i^0) *(x^(n+1))
       = (C(i,0)*x*t0 + C(i,1)*x*t1 + ...+C(i,i)*x*ti)
tj = i^j*(x^n) = g(j,n-1) 0<=j<=i

最终矩阵为(g(0,n),g(1,n),....g(x,n),F(n)) ,乘数矩阵这里略掉,写出来太麻烦,附代码:


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
 
#define N 60
#define cl(a) memset(a,0,sizeof(a))
#define ss(a) scanf("%d",&a) 
#define ll __int64
#define pb push_back

using namespace std;
 
ll a[N][N][N],c[N][N],r[N];
vector<ll>gener;
int mod,k;

void generate_cmb()
{
    int i,j;
    cl(c);
    for (i=0;i<=k;i++)
        for (j=0;j<=i;j++)
        {
            if (j==0) c[i][j]=1;
            else if (j>i-j) c[i][j]=c[i][i-j];
            else c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
}

void init()
{
    int i,j;
    generate_cmb();
    cl(a);cl(r);
    for (i=0;i<=k;i++)
        for (j=0;j<=k;j++)
            a[0][i][j]=(k*c[i][j])%mod;
    for (j=0;j<=k;j++) a[0][k+1][j]=(k*c[k][j])%mod;
    a[0][k+1][k+1]=1;
    for (i=0;i<=k+1;i++) r[i]=k;        
}

void rmul(int x)
{
    int u,v,w;
    for (u=0;u<=k+1;u++)
        for (v=0;v<=k+1;v++)
        {
            for (w=0;w<=k+1;w++) 
                a[x+1][u][v]=(a[x+1][u][v]+(a[x][u][w]*a[x][w][v])%mod)%mod;
        }
}

void mul(int x)
{
    int u,v;
    ll t;
    gener.clear();
    for (u=0;u<=k+1;u++)
    {
        t=0;
        for (v=0;v<=k+1;v++) t=(t+(a[x][u][v]*r[v])%mod)%mod;
        gener.pb(t);
    }
    for (int i=0;i<=k+1;i++) r[i]=gener[i];
}

void quick(int n)
{
    int i=0;
    while (n>0)
    {
        if (n&1) mul(i);
        rmul(i);
        n>>=1;
        i++; 
    } 
}

int main()
{
    int n;
    while (ss(n)!=EOF)
    {
        ss(k);ss(mod);
        if (n<0&&k<0&&mod<0) break;
        if (n==1) 
        {
            cout<<k%mod<<endl;
            continue;
        }
        init();
        quick(n-1);
        cout<<r[k+1]<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值