Description
称一个序列 (a1,b1),(a2,b2),...,(ak,bk) 是美丽的当且仅当其满足以下两个条件
1. 1≤a1≤b1<a2≤b2<...<ak≤bk≤n
2. b1−a1,b2−a2,...,bk−ak 均不同
问满足条件的序列个数
Input
第一行一整数
T
表示用例组数,每组用例输入两个正整数
Output
对于每组用例,输出满足条件的序列个数,结果模 109+7
Sample Input
6
1 1
2 1
2 2
3 1
3 2
3 3
Sample Output
1
3
0
6
2
0
Solution
定义
ci=bi−ai+1
,那么问题变为求满足
ci
互不相同且
∑i=1kci≤n
(由此知
k
最大不超过
前
i
个数的最小值如果是
前
i
个数的最小值如果大于
以此求出
dp
后得到满足
∑l=1jcl≤i,c1<c2<...<cj
的序列
c
的方案数
对于一组查询 n,k ,答案即为 k!⋅ans[n][k]
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define mod 1000000007
int dp[55][1005],ans[1005][55],fact[1005],inv[1005];
void init(int n=1000)
{
fact[0]=1;
for(int i=1;i<=n;i++)fact[i]=(ll)i*fact[i-1]%mod;
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=mod-(ll)(mod/i)*inv[mod%i]%mod;
inv[0]=1;
for(int i=1;i<=n;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
}
int C(int n,int m)
{
return (ll)fact[n]*inv[m]%mod*inv[n-m]%mod;
}
void add(int &x,int y)
{
x=x+y>=mod?x+y-mod:x+y;
}
void init_dp(int n=1000,int k=50)
{
dp[0][0]=1;
for(int i=1;i<=k;i++)
for(int j=i*(i+1)/2;j<=n;j++)
add(dp[i][j],dp[i][j-i]+dp[i-1][j-i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
for(int l=j*(j+1)/2;l<=i;l++)
add(ans[i][j],(ll)dp[j][l]*C(i-(l-j),j)%mod);
}
int main()
{
init();
init_dp();
int T,n,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
if(k<=50)printf("%d\n",(ll)ans[n][k]*fact[k]%mod);
else printf("0\n");
}
return 0;
}