HDU 4602 Partition (矩阵快速幂或求通项)

来源:互联网 发布:美津浓2016跑鞋矩阵 编辑:程序博客网 时间:2024/05/21 10:23

Partition

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3462 Accepted Submission(s): 1348

Problem Description
Define f(n) as the number of ways to perform n in format of the sum of some positive integers. For instance, when n=4, we have
4=1+1+1+1
4=1+1+2
4=1+2+1
4=2+1+1
4=1+3
4=2+2
4=3+1
4=4
totally 8 ways. Actually, we will have f(n)=2(n-1) after observations.
Given a pair of integers n and k, your task is to figure out how many times that the integer k occurs in such 2(n-1) ways. In the example above, number 1 occurs for 12 times, while number 4 only occurs once.

Input
The first line contains a single integer T(1≤T≤10000), indicating the number of test cases.
Each test case contains two integers n and k(1≤n,k≤109).

Output
Output the required answer modulo 109+7 for each test case, one per line.

Sample Input
2
4 2
5 5

Sample Output
5
1

题意

对于一个数n可以拆成题意所给的形式,给你n和k问你k在n所拆成的形式中出现了几次

思路

我们先写一写1 2 3 4 5中各项的值
1 1
2 1 2
3 1 2 5
4 1 2 5 12
5 1 2 5 12 28
写到5我们其实就可以发现值的出现是具有一定规律的,5中有1个5,2个4,5个3,12个2,28个1
然后我们再观察一下这些数会很容易发现:
2=2*1+0
5=2*2+1
12=2*5+2
28=2*12+4(多写一步6中有几个1,会发现是64个)
64=2*28+8
也就是说这些式子从2开始满足:
an=2an1+2n2a1=2,a2=5,n2
原题的n和k可以化成n=n-k
对于an=2an1+2n2我们可以用矩阵快速幂的形式来求解
所构造的矩阵如下
这里写图片描述

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX 3using namespace std;typedef struct{    long long m[MAX][MAX];} Matrix;Matrix P= {2,0,2,0,2,1,0,0,2};Matrix I= {1,0,0,0,1,0,0,0,1};const long long mod=1e9+7;Matrix Matrixmul(Matrix a,Matrix b){    int i,j,k;    Matrix c;    for(i=0; i<MAX; i++)        for(j=0; j<MAX; j++)        {            c.m[i][j]=0;            for(k=0; k<MAX; k++)            {                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;            }            c.m[i][j]%=mod;        }    return c;}Matrix quickpow(long long n){    Matrix m=P,b=I;    while(n>0)    {        if(n%2==1)            b=Matrixmul(b,m);        n=n/2;        m=Matrixmul(m,m);    }    return b;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,k;        scanf("%d%d",&n,&k);        int m=n-k;        if(m<0)        {            printf("0\n");        }        else if(m==0)        {            printf("1\n");        }        else if(m==1)        {            printf("2\n");        }        else if(m==2)        {            printf("5\n");        }        else        {            Matrix A=quickpow(m-2);            printf("%lld\n",(A.m[0][0]*5+A.m[0][1]*2+A.m[0][2]*1)%mod);        }    }    return 0;}

然后说说怎么求解通项
an2an1=2n2可以利用线性非齐次递推关系的方法来求解也可以用构造等差数列的方式求解,先说线性非齐次递推关系的方法

  • 线性非齐次递推关系
    an2an1=2n2可得到特征方程
    x22x=0,解得x=2,x=0
    特征根为一重根
    所以特解an=kn2n2,代入原式得k=1
    那么有an=(An+B)2n+n2n2,再代入a2=5,a3=12
    A=0B=34
    那么有an=(3+n)2n2,,n2

  • 构造等差数列
    an2an=2n2两边同时除以2n

    an2nan12n1=14
    所以有
    an2n=54+(n2)14
    那么
    an=542n+(n2)142n

    an=(3+n)2n2,,n2

#include <iostream>#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string.h>using namespace std;const long long mod=1e9+7;long long quickmod(long long n){    long long ans=1;    long long a=2;    while(n>0)    {        if(n%2==1)            ans=(ans*a)%mod;        a=a*a%mod;        n/=2;    }    return ans;}int main(){    int t;    scanf("%d",&t);    while(t--)    {        long long n,k;        scanf("%lld%lld",&n,&k);        if(n-k<0)            printf("0\n");        else if(n-k==0)            printf("1\n");        else if(n-k==1)            printf("2\n");        else        {            n=n-k;            printf("%lld\n",(n+3)*quickmod(n-2)%mod);        }    }    return 0;}
原创粉丝点击