您的位置:首页 > 其它

HDU 4602 Partition(快速幂)

2015-07-24 19:14 381 查看
C - Partition
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d
& %I64d

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≤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


题目大意:给出一个数n,按照题目的分解成公式,求数k在所有公式中出现的次数。

找规律

1=1

1:1个

2=1+1

2=2

1:2个

2:1个

3=1+1+1

3=1+2

3=2+1

3=3

1:5个

2:2个

3:1个

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

1:12 个

2;5个

3:2个

4:1个

5=1+1+1+1+1

5=1+1+1+2

5=1+1+2+1

5=1+2+1+1

5=2+1+1+1

5=1+1+3

5=1+3+1

5=3+1+1

5=1+2+2

5=2+1+2

5=2+2+1

5=2+3

5=3+2

5=1+4

5=4+1

5=5

1:28个

2:12个

3:5个

4:2个

5:1个

分析:

当k > n时,结果为0;
当k = n时,结果为1;
当k < n时,把n分成n个1即n=1+1+······+1+1,要想得到一个k即取出k个连续的1组成1个k即可。
设取出来的这k个1的第一位是x,则x的左边有(x-1)个1,根据题意可知,将(x-1)拆分共有2^(x-2)种拆分法,区间[x, x+k-1]所包含的1是取的连续的k个1,它的右边还有[n - (x+k-1)]个1,[n - (x+k-1)]有2^[n - (x+k-1) - 1] = 2^(n-b-k)种拆分法。因此,当取定这个位置的k时,有2^(x-2)
* 2^(n-x-k) = 2^(n-k-2)种情况(注意结果与x无关)。这里没有重复,因为计算每个位置的k只计算他自己一次,而不管其他地方是否也出现了k。
当x = 1时,x的左边没有1,右边有2^(n-b-k) = 2^(n-1-k)种拆分;
当x = n-k+1时,组成的k的右边没有1,左边有2^(b-2) = 2^(n-1-k)种拆分;
当2 <= x <= n-k时,就有(n-k-2+1) * 2^(x-2) * 2^(n-x-k)种拆分;
一共就是2^(n-b-k) + 2^(n-1-k) + (n-k-2+1) * 2^(b-2) * 2^(n-b-k) = (n-k+3)*2^(n-k-2)

注意由于数据比较大,因此用快速幂求解。

// m^n % k
int quickpow(int m,int n,int k)
{
int b = 1;
while (n > 0)
{
if (n & 1)
b = (b*m)%k;
n = n >> 1 ;
m = (m*m)%k;
}
return b;
}


AC代码如下:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-4)
#define inf (1<<28)
#define sqr(x) (x) * (x)
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
#define M 1000000007
long long quickpow(long long m,long long n,long long k)//注意数据类型long long型
{
int b = 1;
while (n > 0)
{
if (n & 1)
b = (b*m)%k;
n = n >> 1 ;
m = (m*m)%k;
}
return b;
}
int main()
{
long long i,t,n,k;
scanf("%d",&t);
while(t--)
{
scanf("%ld%ld",&n,&k);
if(k>n)
printf("0\n");
else if(n==k)
printf("1\n");
else if(k==n-1)
printf("2\n");
else
printf("%ld\n",(n-k+3)*quickpow(2,n-k-2,M)%M);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: