三月校赛1006 wuli通通和Fibonacci (a[n]=f[n]*(n^m)的前k项和)

题目链接:
校赛 1006 wuli通通和Fibonacci
题意:
a[n]=f[n](nm)kmod23333f[n]Fibonaccif[1]=f[2]=1,k<=1e9,m<=40
分析:
mod23333m<=40mmmn,(n1)mnm

nm=((n1)+1)m=C[m][m](n1)m+C[m][m1](n1)(m1)+C[m][m2](n1)(m2)+...+C[m][1](n1)(1)+C[m][0](n1)(0);C[i][j]

那么就可以构造出如下矩阵了:

| C[m][0]    0         0        0    ...    0   |   | (n-1)^(0)  |   | n^0 |
| C[m][0]  C[m][1]     0        0    ...    0   |   | (n-1)^(1)  |   | n^1 |
| C[m][0]  C[m][1]  C[m][2]     0    ...    0   | * | (n-1)^(2)  | = | n^2 |
| C[m][0]  C[m][1]  C[m][2]  C[m][3] ...    0   |   | (n-1)^(3)  |   | n^3 |
|    .   .   .      .   .  .    .    .    . .   |   | .  .   .  .|   | . . |
| C[m][0]  C[m][1]  C[m][2]  C[m][3] .. C[m][m] |   | (n-1)^(m)  |   | n^m |

再想办法将Fibonacci数列添加进去,一开始我是想在构造一个右乘矩阵,如下:

| C[m][0]     0          0         0    ...       0   |    | f[n-1](n-1)^(0)  f[n-1](n-2)^(0) |
| C[m][0]   C[m][1]      0         0    ...       0   |    | f[n-1](n-1)^(1)  f[n-1](n-2)^(1) |
| C[m][0]   C[m][1]   C[m][2]      0    ...       0   |  * | f[n-1](n-1)^(2)  f[n-1](n-2)^(2) |
| C[m][0]   C[m][1]   C[m][2]   C[m][3] ...       0   |    | f[n-1](n-1)^(3)  f[n-1](n-2)^(3) |
|    .   .    .    .   .   .   .    .    .    .   .   |    | .  .   .  .       .    .   .  .  |
| C[m][0]   C[m][1]   C[m][2]   C[m][3] ...   C[m][m] |    | f[n-1](n-1)^(m)  f[n-1](n-2)^(m) |
|         |  
      |  1  1   |  
   *  |         | 
      |         |  = 
      |  1   0  |   
      |         |    
| f[n](n-1)^(0)  f[n-1](n-1)^(0) |
| f[n](n-1)^(1)  f[n-1](n-1)^(1) |
| f[n](n-1)^(2)  f[n-1](n-1)^(2) |
| f[n](n-1)^(3)  f[n-1](n-1)^(3) |
| .  .  .  .  .  .  .  .  .  . . |
| f[n](n-1)^(m)  f[n-1](n-1)^(m) |

但是这样就发现有一个问题那就是我无法再通过添加一维的方法将a[n]的和这一项添加进中间矩阵。
后来又想了到了一个方法,可以将上面的中间(m+1)2阶矩阵拉伸成(2(m+1))*阶矩阵,也就是这样:

| f[n-1](n-1)^(0) |
| f[n-1](n-2)^(0) |
| f[n-1](n-1)^(1) |
| f[n-1](n-2)^(1) |
| f[n-1](n-1)^(2) |
| f[n-1](n-2)^(2) |
| f[n-1](n-1)^(3) | 
| f[n-1](n-2)^(3) |
|  .  .   .  .    |  
|  .    .   .  .  |
| f[n-1](n-1)^(m) |
| f[n-1](n-2)^(m) |

然后再将左面的矩阵也跟着变一下:

| C[m][0]   C[m][0]      0         0    ...       0       0    |
| C[m][0]      0         0         0    ...       0       0    |
| C[m][0]   C[m][0]   C[m][1]   C[m][1] ...       0       0    |
| C[m][0]   C[m][1]      0         0    ...       0       0    |
|    .   .    .    .   .   .   .    .    .    .   .       0    |   
| C[m][0]   C[m][0]   C[m][1]   C[m][1] ...   C[m][m]  C[m][m] |
| C[m][0]      0      C[m][1]      0    ...   C[m][m]     0    |

最后再在最后一维各添加一行(注意维数都变了):

|   S[n-2]  | 
和
| C[m][0]   C[m][0]   C[m][1]   C[m][1] ...   C[m][m]  C[m][m]  1 | 

就行了。【好累。。。o(╯□╰)o】

#include <cstdio>
#include <cstring>
using namespace std;

const long long mod=23333;
const int maxn=45;
int T,m,k;
long long c[maxn][maxn];

struct Matrix{
    int row,col;
    long long data[maxn*2][maxn*2];
};

inline void calc()
{
    for(int i=0;i<=42;i++){
        for(int j=0;j<=i;j++){
            if(j==0) c[i][j]=1;
            else c[i][j]=c[i][j-1]*(i-j+1)/j;
        }
    }
}

inline Matrix mul(Matrix a,Matrix b)
{
    Matrix ans;
    ans.row=a.row,ans.col=b.col;
    memset(ans.data,0,sizeof(ans.data));
    for(int i=1;i<=ans.row;i++){
        for(int j=1;j<=ans.col;j++){
            for(int k=1;k<=a.col;k++){
                ans.data[i][j]+=a.data[i][k]*b.data[k][j]%mod;
                ans.data[i][j]%=mod;
            }
        }
    }
    return ans;
}

inline Matrix quick_power(Matrix a,int time)
{
    Matrix ans,tmp=a;
    ans.row=ans.col=a.row;
    memset(ans.data,0,sizeof(ans.data));
    for(int i=1;i<=ans.row;i++) ans.data[i][i]=1;
    while(time){
        if(time&1) ans=mul(ans,tmp);
        tmp=mul(tmp,tmp);
        time>>=1;
    }
    return ans;
}

int main()
{
    //freopen("1006in.txt","r",stdin);
    //freopen("1006out.txt","w",stdout);
    calc();
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&k,&m);
        if(k==1){
            printf("1\n");
            continue;
        }
        Matrix ans,tmp;
        ans.row=ans.col=tmp.row=2*m+3,tmp.col=1;
        memset(ans.data,0,sizeof(ans.data));
        for(int i=1;i<=m+1;i++){
            for(int j=1;j<=i;j++){
                ans.data[2*i-1][2*j-1]=ans.data[2*i-1][2*j]=ans.data[2*i][2*j-1]=c[i-1][j-1];
                ans.data[2*i][2*j]=0;
            }
        }
        for(int i=1;i<=m+1;i++) ans.data[2*m+3][2*i-1]=ans.data[2*m+3][2*i]=c[m][i-1];
        ans.data[2*m+3][2*m+3]=1;
        for(int i=1;i<=m*2+2;i+=2) {
            tmp.data[i][1]=1;
            tmp.data[i+1][1]=0;
        }
        tmp.data[2*m+3][1]=1;
        ans=quick_power(ans,k-1);
        tmp=mul(ans,tmp);
        printf("%I64d\n",tmp.data[2*m+3][1]%mod);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值