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=21+0
5=22+1
12=25+2
28=212+4(多写一步6中有几个1,会发现是64个)
64=2*28+8
也就是说这些式子从2开始满足:
a
n
=
2
a
n
−
1
+
2
n
−
2
a_{n}=2a_{n-1}+2^{n-2}
an=2an−1+2n−2,
a
1
=
2
,
a
2
=
5
a_{1}=2,a_{2}=5
a1=2,a2=5,
n
≥
2
n\geq 2
n≥2
原题的n和k可以化成n=n-k
对于
a
n
=
2
a
n
−
1
+
2
n
−
2
a_{n}=2a_{n-1}+2^{n-2}
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;
}
然后说说怎么求解通项
a
n
−
2
a
n
−
1
=
2
n
−
2
a_{n}-2a_{n-1}=2^{n-2}
an−2an−1=2n−2可以利用线性非齐次递推关系的方法来求解也可以用构造等差数列的方式求解,先说线性非齐次递推关系的方法
-
线性非齐次递推关系
由 a n − 2 a n − 1 = 2 n − 2 a_{n}-2a_{n-1}=2^{n-2} an−2an−1=2n−2可得到特征方程
x 2 − 2 x = 0 x^2-2x=0 x2−2x=0,解得x=2,x=0
特征根为一重根
所以特解 ∗ a n = k n 2 n − 2 \ast a_{n}=kn2^{n-2} ∗an=kn2n−2,代入原式得k=1
那么有 a n = ( A n + B ) 2 n + n 2 n − 2 a_{n}=(An+B)2^{n}+n2^{n-2} an=(An+B)2n+n2n−2,再代入 a 2 = 5 , a 3 = 12 a_{2}=5,a_{3}=12 a2=5,a3=12
得 A = 0 , B = 3 4 A=0,B=\frac{3}{4} A=0,B=43
那么有 a n = ( 3 + n ) 2 n − 2 a_{n}=(3+n)2^{n-2} an=(3+n)2n−2, n ≥ 2 n\geq 2 n≥2 -
构造等差数列
a n − 2 a n = 2 n − 2 a_{n}-2a_{n}=2^{n-2} an−2an=2n−2两边同时除以 2 n 2^{n} 2n
有
a
n
2
n
−
a
n
−
1
2
n
−
1
=
1
4
\frac{a_{n}}{2^{n}}-\frac{a_{n-1}}{2^{n-1}}=\frac{1}{4}
2nan−2n−1an−1=41
所以有
a
n
2
n
=
5
4
+
(
n
−
2
)
1
4
\frac{a_{n}}{2^{n}}=\frac{5}{4}+(n-2)\frac{1}{4}
2nan=45+(n−2)41
那么
a
n
=
5
4
2
n
+
(
n
−
2
)
1
4
2
n
a_{n}=\frac{5}{4}2^{n}+(n-2)\frac{1}{4}2^{n}
an=452n+(n−2)412n
即
a
n
=
(
3
+
n
)
2
n
−
2
a_{n}=(3+n)2^{n-2}
an=(3+n)2n−2,
n
≥
2
n\geq 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;
}