您的位置:首页 > 其它

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

2017-12-04 12:59 337 查看
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=2an−1+2n−2,a1=2,a2=5,n≥2

原题的n和k可以化成n=n-k

对于an=2an−1+2n−2我们可以用矩阵快速幂的形式来求解

所构造的矩阵如下



#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 3
using 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;
}


然后说说怎么求解通项

an−2an−1=2n−2可以利用线性非齐次递推关系的方法来求解也可以用构造等差数列的方式求解,先说线性非齐次递推关系的方法

线性非齐次递推关系

由an−2an−1=2n−2可得到特征方程

x2−2x=0,解得x=2,x=0

特征根为一重根

所以特解∗an=kn2n−2,代入原式得k=1

那么有an=(An+B)2n+n2n−2,再代入a2=5,a3=12

得A=0,B=34

那么有an=(3+n)2n−2,,n≥2

构造等差数列

an−2an=2n−2两边同时除以2n

有an2n−an−12n−1=14

所以有

an2n=54+(n−2)14

那么

an=542n+(n−2)142n



an=(3+n)2n−2,,n≥2

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: