HDU 2294解题报告

Pendant

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


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
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  3117 2256 2842 3519 3524 

         这道题是一道比较经典的矩阵优化DP的题,非常经典,是很值得钻研的一道题。

         这道题的意思是给你k种珍珠,用k种珍珠串成长度为1,2~n的方法数之和。

         我们可以用dp[i][j]表示用j中珍珠构成长度为i的项链的方法总数。则我们考虑长度为i-1的项链的情况,此时我们如果用j种珍珠构成了长度为i-1的项链,那么用j种珍珠构成长度为i的项链时,需要再对长度为i-1的项链再加上的珍珠是j种珍珠之中一种,所以此时构成长度为i的项链共有dp[i-1][j]*j种,当然还有一种情况是用j-1种珍珠构成长度为i-1的项链,那么要用j中珍珠构成长度为i的项链,就只需要给长度为i-1的项链再添加上剩下(k-j+1)种中的一种,所以此时构成长度为i的项链有dp[i-1][j-1]*(k-j+1)。 

       因此可以写出状态转移方程,dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]*(k-j+1)。

       根据这个状态转移方程以及n的数量级,我们就要想到用矩阵快速幂来加速dp的过程。但是进行矩阵快速幂时我们需要求的值是dp[k][1]+dp[k][2]+……+dp[k][n]的值。如果在构造矩阵时只是对单个dp的值进行记录的话,那么就势必要对矩阵多项式进行求解。但是如果采用二分矩阵多项式进行递归求解容易导致递归次数太多,出现栈溢出。因而要在矩阵快速幂时就计算dp之和的值,这样只用一次矩阵快速幂即可求出所有dp的和。

       因此在做和矩阵相关的题的时候就需要格外注意,如果可以一次性通过矩阵快速幂求出某个式子之和,那么就尽可能不要去使用二分矩阵多项式。因此要构造性能更优的矩阵,来降低时间复杂度。这一点需要好好体会才行。如何构造矩阵还是很值得思考的知识点。

         参考代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<iomanip>
#include<utility>
#define pb push_back
#define mp make_pair
#define CLR(x) memset(x,0,sizeof(x))
#define _CLR(x) memset(x,-1,sizeof(x))
#define REP(i,n) for(int i=0;i<n;i++)
#define Debug(x) cout<<#x<<"="<<x<<" "<<endl
#define REP(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=l;i<r;i++)
#define RREP(i,l,r) for(int i=l;i>=r;i--)
#define rrep(i,l,r) for(int i=1;i>r;i--)
#define read(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<11
using namespace std;

const int mod=1234567891;

struct mat
{
    ll d[35][35];
}A,B,E;

int t,n,k;

mat multi(const mat &a,const mat &b)
{
    mat ans;
    REP(i,0,k+1)
    {
        REP(j,0,k+1)
        {
            ans.d[i][j]=0;
            REP(l,0,k+1)
            {
                if(a.d[i][l]&&b.d[l][j])
                    ans.d[i][j]=(ans.d[i][j]+a.d[i][l]*b.d[l][j])%mod;
            }
        }
    }
    return ans;
}

mat quickmulti(mat a,int n)
{
    if(n==0) return E;
    if(n==1) return a;
    mat ans=E;
    while(n)
    {
        if(n&1)
        {
            n--;
            ans=multi(ans,a);
        }
        else
        {
            n>>=1;
            a=multi(a,a);
        }
    }
    return ans;
}

int main()
{
   CLR(E.d);
   REP(i,0,32)
     E.d[i][i]=1;
   read(t);
   while(t--)
   {
       read(n);read(k);
       CLR(A.d);CLR(B.d);
       A.d[k+1][k+1]=1,A.d[k+1][k-1]=1,A.d[k+1][k]=k; //这几个值是为了最终就算出所有的dp之和
       REP(i,1,k)
           A.d[i][i-1]=k-i+1,A.d[i][i]=i;
       B.d[1][0]=k;B.d[k+1][0]=0;
       if(k==1) B.d[k+1][0]=1;           //B.d[k+1][0]这个记录的是dp[k][1]的值,这也是最初始状态的值。但是当k==1时,dp[1][0]=1,所以这个情况比较特殊
       mat ans=quickmulti(A,n-1);
       ans=multi(ans,B);
       printf("%I64d\n",ans.d[k+1][0]);
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章