原题链接:
hdu
题意简述
一个数 n n n珂以被分成若干个数的和的形式。
比如 n = 4 n=4 n=4时,分解有:
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
然后你要求在这些个分解中, k k k出现了多少次。
数据
输入
t//数据组数(这题多组)
n k
n k
...
n k//一次,n,k<=1e9
输出
ans
ans
...
ans//输出每个的答案,要膜1e9+7
样例
输入
2
4 2
5 5
输出
5
1
思路
我们会发现,一个数 n n n中出现 k k k,可能是一下几种情况:
- 在中间的情况
其中 k k k是确定的,左右两边的 a , b a,b a,b满足: a , b > 0 a,b>0 a,b>0且 a + b = n − k a+b=n-k a+b=n−k。然后我们发现,确定了 a a a就确定了 b b b,而且 a a a是有范围的, 0 < a < n − k 0<a<n-k 0<a<n−k。所以我们考虑枚举 a a a,求出 b b b,进而求出情况数,然后求和。
对于我们当前枚举的 a a a,情况数为:
左边: 2 ( a − 1 ) 2^{(a-1)} 2(a−1)种(把 a a a因为中间已经有 k k k了,所以 a a a想怎么拆,就怎么拆)
中间: 1 1 1(确定了)
右边: 2 ( b − 1 ) 2^{(b-1)} 2(b−1)种(同理, b b b想怎么拆,也就怎么拆了)
根据乘法原理,共有 2 a − 1 ∗ 2 b − 1 ∗ 1 = 2 a − 1 + b − 1 = 2 n − k − 2 2^{a-1}*2^{b-1}*1=2^{a-1+b-1}=2^{n-k-2} 2a−1∗2b−1∗1=2a−1+b−1=2n−k−2种。
我们发现这 t m tm tm的是个定值。所以我们直接乘上去就好了。 a a a在 ( 0 , n − k ) (0,n-k) (0,n−k)之间(注意是开集),所以 a a a有 n − k − 2 n-k-2 n−k−2种取值。所以情况 1 1 1的总答案就是 2 n − k − 2 ∗ ( n − k − 1 ) 2^{n-k-2}*(n-k-1) 2n−k−2∗(n−k−1)。
2.在两边的情况:
这两种情况其实是一样的,只是位置不一样,算出来一个,乘二就珂以了。其中一个的答案:
确定的部分(
k
k
k):
1
1
1
不确定部分(
n
−
k
n-k
n−k):
2
n
−
k
−
1
2^{n-k-1}
2n−k−1
然后再乘二就好了。我们会发现珂以合并同类项,变成:
2
n
−
k
2^{n-k}
2n−k
综上,答案就是 2 n − k + 2 n − k − 2 ∗ ( n − k − 1 ) 2^{n-k}+2^{n-k-2}*(n-k-1) 2n−k+2n−k−2∗(n−k−1)
然后就是快速幂模板了。代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define mod 1000000007ll
#define int long long
int qpow(int a,int b,int m=mod)
{
if (b<0) return 0;
int r=1;
while(b)
{
if (b&1)
{
r=r*a%m;
}
a=a*a%m;
b>>=1;
}
return r;
}
int n,k;
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void P1(int x)
{
if (x>=0 and x<=9)
{
putchar(x+'0');
return;
}
P1(x/10);
putchar(x%10+'0');
}
void Input()
{
R1(n),R1(k);
}
void Soviet()
{
if (n==k)
{
puts("1");
return;
}
int ans=qpow(2,n-k);
ans+=qpow(2,n-k-2)*(n-k-1);
ans%=mod;
P1(ans);putchar('\n');
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
int t;R1(t);
while(t--)
{
Input();
Soviet();
}
}
#undef int //long long
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}