[HDU2294] Pendant - 矩阵加速递推

Pendant

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1032    Accepted Submission(s): 535

Problem Description

On
Saint Valentine‘s Day, Alex imagined to present a special pendant to
his girl friend made by K kind of pearls. The pendant is actually a
string of pearls, and its length is defined as the number of pearls in
it. As is known to all, Alex is very rich, and he has N pearls of each
kind. Pendant can be told apart according to permutation of its pearls.
Now he wants to know how many kind of pendant can he made, with length
between 1 and N. Of course, to show his wealth, every kind of pendant
must be made of K pearls.
Output the answer taken modulo 1234567891.

Input

The
input consists of multiple test cases. The first line contains an
integer T indicating the number of test cases. Each case is on one line,
consisting of two integers N and K, separated by one space.
Technical Specification

1 ≤ T ≤ 10
1 ≤ N ≤ 1,000,000,000
1 ≤ K ≤ 30

Output

Output the answer on one line for each test case.

Sample Input

2
2 1
3 2

Sample Output

2
8

Source

The 4th Baidu Cup final

Recommend

lcy   |   We have carefully selected several similar problems for you:  1588 3117 2971 2256 1757


题解:

设f[i][j] 表示长度为i,用了j种珍珠的方案个数;

我们考虑加一个位置,我们可以让它是之前出现过的珍珠,也可以是没出现过的珍珠;

f[i][j] = (k-(i-1))*f[i-1][j-1] + j*f[i-1][j];

我们发现这个dp是O(nk)的,n变态的大显然炸掉;

看到n自然而然的会想到矩阵加速;

我们设一个转移矩阵是G,G[k+1][k+1], 为什么是k+1?

我们要算总的方案个数,要把所有的f[i][k]加起来,所以我们多开一维,用来转移f[i][k]的和;

G的矩阵长这样

1 0 0 0 0 1      sum    sum‘  

0 1 0 0 0 1      f1     f1‘

0 k-1 2 0 0 0    *     f2  ->   f2‘

...          ...    ...

0 0 0 0 1 k      fk     fk‘

就这样


Code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ll long long
#define mod 1234567891
#define N 32
int T;
ll n, k;

struct Mat
{
    ll a[N][N];
    Mat() {memset(a, 0, sizeof a);}
    inline void clear() {memset(a, 0, sizeof a);}
    inline void ini() {for(int i=0;i<=k;i++)a[i][i]=1;}
    friend Mat operator * (Mat x, Mat y)
    {
        Mat z;
        for (register int p = 0 ; p <= k ; p ++)
        {
            for (register int i = 0 ; i <= k ; i ++)
            {
                for (register int j = 0 ; j <= k ; j ++)
                {
                    z.a[i][j] = (z.a[i][j] + x.a[i][p] * y.a[p][j]) % mod;
                }
            }
        }
        return z;
    }
    friend Mat operator ^ (Mat x, ll y)
    {
        Mat z;z.ini();
        while (y)
        {
            if (y & 1) z = z * x;
            x = x * x;
            y >>= 1;
        }
        return z;
    }
}G, B, C;
inline void init() {G.clear(), B.clear(), C.clear();}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        init();
        scanf("%lld%lld", &n, &k);
        G.a[0][0] = 1, G.a[0][k] = 1;
        G.a[1][1] = 1;
        for (register int i = 2 ; i <= k ; i ++)
        {
            G.a[i][i] = i;
            G.a[i][i-1] = k - i + 1;
        }
    //    for (int i=0;i<=k;i++,puts(""))for(int j=0;j<=k;j++) printf("%d ",G.a[i][j]) ;
        B.a[1][0] = k;
        C = G ^ n;
        C = C * B;
        cout<<C.a[0][0]<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zZh-Brim/p/9261106.html

时间: 2024-11-02 15:57:18

[HDU2294] Pendant - 矩阵加速递推的相关文章

矩阵经典题目七:Warcraft III 守望者的烦恼(矩阵加速递推)

https://www.vijos.org/p/1067 很容易推出递推式f[n] = f[n-1]+f[n-2]+......+f[n-k]. 构造矩阵的方法:构造一个k*k的矩阵,其中右上角的(k-1)*(k-1)的矩阵是单位矩阵,第k行的每个数分别对应f[n-1],f[n-2],,f[n-k]的系数.然后构造一个k*1的矩阵,它的第i行代表f[i],是经过直接递推得到的.设ans[][]是第一个矩阵的n-k次幂乘上第二个矩阵,f[n]就是ans[k][1]. 注意:用__int64 #in

HDU 3117 Fibonacci Numbers(Fibonacci矩阵加速递推+公式)

题目意思很简单:求第n个Fibonacci数,如果超过八位输出前四位和后四位中间输出...,否则直接输出Fibonacci数是多少. 后四位很好求,直接矩阵加速递推对10000取余的结果就是. 前四位搜了一下:http://blog.csdn.net/xieqinghuang/article/details/7789908 Fibonacci的通项公式,对,fibonacci数是有通项公式的-- f(n)=1/sqrt(5)(((1+sqrt(5))/2)^n+((1-sqrt(5))/2)^n

[LGOJ]P1939【模板】矩阵加速(数列)[矩阵加速递推]

题面 矩阵加速递推的原理: 首先你得会矩阵乘法与快速幂. 以斐波拉契数列为例, 要从矩阵A \[ \begin{bmatrix} f[n-1] & f[n]  \end{bmatrix} \] 得到矩阵B \[ \begin{bmatrix} f[n] & f[n+1]  \end{bmatrix} \] 显然可以\[\begin{bmatrix} f[n-1] & f[n] \end{bmatrix}\times \begin{bmatrix}  0 & 1\\ 1 &a

HDU 4686 Arc of Dream(矩阵加速递推)

题目大意:就是给你你个有两个递推公式乘起来的式子,让你求出第n项的结果. 注意这种递推的需要把式子乘起来然后再构造矩阵. Arc of Dream Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 2092    Accepted Submission(s): 664 Problem Description An Arc of Dream

HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers

POJ3070 Fibonacci(矩阵快速幂加速递推)【模板题】

题目链接:传送门 题目大意: 求斐波那契数列第n项F(n). (F(0) = 0, F(1) = 1, 0 ≤ n ≤ 109) 思路: 用矩阵乘法加速递推. 算法竞赛进阶指南的模板: #include <iostream> #include <cstring> using namespace std; const int MOD = 10000; void mul(int f[2], int base[2][2]) { int c[2]; memset(c, 0, sizeof

矩阵乘法递推的优化艺术

对于一个线性递推式,求它第项的值,通常的做法是先构造一个的矩阵,然后在时间内求出. 其实,由于这个矩阵的特殊性,可以将时间优化到.接下来我会以一个题目来讲解矩阵乘法递推的优化. 题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1229 题意:设,求的值.其中,和 . 前言:本题如果用普通的矩阵做法,很明显会TLE.那么我们要对这个特殊的矩阵进行时间上的优化. 分析:本题主要可用两种方法解决,分别是错位相减和矩阵乘法

HDU 4914 Linear recursive sequence(矩阵乘法递推的优化)

题解见X姐的论文 矩阵乘法递推的优化,只是mark一下.. HDU 4914 Linear recursive sequence(矩阵乘法递推的优化)

矩阵乘法来加速递推式计算

Codevs1281: 给你6个数,m, a, c, x0, n, g Xn+1 = ( aXn + c ) mod m,求Xn 计算递推式,运用矩阵来进行计算加速 然后注意用类似快速幂的方法写一个快速加,避免溢出 怎么把式子化成矩阵,日后再补 1 #include<cstdio> 2 long long mod,a,c,x0,n,g; 3 struct Mat 4 { 5 long long m[2][2]; 6 }base,X0; 7 long long quick_add(long lo