Partition
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1077 Accepted Submission(s): 439
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.
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≤10 9).
Each test case contains two integers n and k(1≤n,k≤10 9).
Output
Output the required answer modulo 10
9+7 for each test case, one per line.
Sample Input
2 4 2 5 5
Sample Output
5 1
Source
Recommend
liuyiding
感言:
当时,比赛时。一直没往排列组合问题上考虑。可能被题目跟队友说是DP误导了吧。更多的是自己水平不足吧。 平时做的题目,排列组合做的太少了。没一眼看出来。
直接附上标准题解吧,已经讲的很详细了。
Problem C. Partition
我们可以特判出 n <= k 的情况。
对于 1 <= k < n,我们可以等效为 n 个点排成一列,并取出其中的连续 k 个点。下面分两种
情况考虑:
第一种情况,被选出的不包含端点,那么有(n – k − 1)种情况完成上述操作,剩下未被圈的点
之间还有(n – k − 2)个位置,可以在每个位置断开,所以共 2^(n−k−2) ∗ (n−k−1)种方法。
第二种情况,即被选出的包含端点,那么有 2 种情况,并且剩余共(n – k − 1)个位置,所以共
2 ∗ 2^(n – k − 1)种方法。
总计 2 ∗ 2^(n – k − 1) + 2^(n – k − 2) ∗ (n – k − 1) = (n – k + 3) * 2^(n – k − 2)。
我们可以特判出 n <= k 的情况。
对于 1 <= k < n,我们可以等效为 n 个点排成一列,并取出其中的连续 k 个点。下面分两种
情况考虑:
第一种情况,被选出的不包含端点,那么有(n – k − 1)种情况完成上述操作,剩下未被圈的点
之间还有(n – k − 2)个位置,可以在每个位置断开,所以共 2^(n−k−2) ∗ (n−k−1)种方法。
第二种情况,即被选出的包含端点,那么有 2 种情况,并且剩余共(n – k − 1)个位置,所以共
2 ∗ 2^(n – k − 1)种方法。
总计 2 ∗ 2^(n – k − 1) + 2^(n – k − 2) ∗ (n – k − 1) = (n – k + 3) * 2^(n – k − 2)。
就是最后要用下快速幂算法。
/*
* @author ipqhjjybj
* @date 20130725
*
*/
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <numeric>
#include <utility>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <string>
using namespace std;
#define inf 0x3f3f3f3f
#define MAXN 100005
#define clr(x,k) memset((x),(k),sizeof(x))
#define clrn(x,k) memset((x),(k),(n+1)*sizeof(int))
#define cpy(x,k) memcpy((x),(k),sizeof(x))
#define Base 10000
typedef vector<int> vi;
typedef stack<int> si;
typedef vector<string> vs;
#define sz(a) int((a).size())
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define rep(i,n) for(int i = 0;i < n;++i)
#define foreach(it,c) for(vi::iterator it = (c).begin();it != (c).end();++it)
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define ll long long
const int MOD=1e9+7;
ll quick_mod(ll base,ll n){
ll ret=1;
while(n){
if(n&1)
ret=ret*base%MOD;
base=base*base%MOD;
n>>=1;
}
return ret;
}
int main(){
int t;
int n,k;
ll ans;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&k);
if(k>n) ans=0;
else if(k==n) ans=1;
else if(k==n-1) ans=2;
else ans=(long long)(n-k+3)*quick_mod(2,n-k-2)%MOD;
cout<<ans<<endl;
}
return 0;
}