hdu 3483(矩阵)

此题题意很简单:就是求下面这个式子

x 取1-50 M,N取1-2×10^9

//首先可以看出这要用矩阵

但自己搞没搞出来,至于为什么,下文会提到,看了大牛报告,恍然大悟,自感弱菜。。。
//S(n) = sum(k^x * x^k)
//S(n+1)  = S(n) + (n+1)^x * x^(n+1);
//        = S(n) + x^(n+1) * ((x,0)*n^0 + (x,1)*n^1 + (x,2)*n^2,...二项展开)
//据此构造向量
//T(n) =  (x^n*n^0,x^n*n^1,x^n*n^2,...x^n*n^x,S(n))
//T(n+1) =(x^(n+1)*(n+1)^0,x^(n+1)*(n+1)^1... x^(n+1)*n^(x+1),S(n+1));
//在这纸上乱搞一下可得出,(但我刚开始没想出(1+n)^x 可以用二项展开式来代替,所以。。)
//矩阵为
//x*(0,0) x*(1,0) x*(2,0) ... x*(x,0) x*(x,0)
//0       x*(1,1) x*(2,1) ... x*(x,1) x*(x,1)
//0       0       x*(2,2) ... x*(x,2) x*(x,2)
//.
//.
//.
//0       0       0       ... 0       1

贴代码:

#include <cstdio>
#include <cstring>


typedef __int64 ll;
const int size = 60;
ll M;
struct Matrix{
    ll a[size][size];
    int r,c; //行列
    Matrix(){};
    Matrix(int v)
    {
        for(int i = 0; i < size; i++)
            for(int j = 0; j < size; j++)
                if(i == j) a[i][j] = v;
                else a[i][j] = 0;
    }
    void print()
    {
        for(int i = 0; i < r; i++){
            for(int j = 0; j < c; j++)
                printf("%lld ",a[i][j]);
            printf("\n");
        }
    }
};


Matrix operator * (Matrix &ma,Matrix &mb)
{
    Matrix mc(0);
    for(int i = 0; i < ma.r; i++)
        for(int j = 0; j < mb.c; j++)
            for(int k = 0; k < ma.c; k++)
                mc.a[i][j] = (mc.a[i][j] + ma.a[i][k] * mb.a[k][j]) % M;
    mc.r = ma.r;
    mc.c = mb.c;
    return mc;
}
Matrix operator ^ (Matrix &a,int b)
{
    Matrix ans(1);
    ans.c = a.c;
    ans.r = a.r;
    while(b){
        if(b & 1) ans = ans * a;
        a = a * a;
        b >>= 1;
    }
    return ans;
}
ll cb[size][size];
void init_cb(void)
{
    for(int i = 0; i < size; i++){
        cb[0][i] = 0;
        cb[i][0] = 1;
    }
    for(int i = 1; i < size; i++)
        for(int j = 1; j < size; j++)
            cb[i][j] = cb[i-1][j] + cb[i-1][j-1];
}
void build_matrix(Matrix &A,Matrix &T,int x)
{
    A.r = x + 2;
    A.c = x + 2;
    for(int i = 0; i < A.r; i++)
        for(int j = i; j < A.c-1; j++){
            A.a[i][j] = x * cb[j][i] % M;
        }
    for(int i = 0; i < A.r; i++)
        A.a[i][A.c-1] = A.a[i][A.c-2];
    A.a[A.r-1][A.c-1] = 1;
    ///
    T.r = 1;T.c = x+2;
    for(int i = 0; i < T.c; i++)
        T.a[0][i] = x;
}


int main()
{
    ll N,x;
    while(1){
        scanf("%I64d%I64d%I64d",&N,&x,&M);
        if(N < 0) break;
        init_cb();
        Matrix A,T;
        build_matrix(A,T,x);
     //   A.print(); T.print();
        A = A ^ (N-1);
        T = T * A;
      //  T.print();
        printf("%I64d\n",T.a[0][T.c-1]);
    }
    return 0;
}


这题还得到一个小经验,用long long会tle,用__int64就A了,不知道为什么。。。,以后能用__int64就用__int64啊。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值