http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=891&pid=1005
http://acm.hdu.edu.cn/showproblem.php?pid=6787
设f[i][j],为可以恰好踩到到第j个位置,前面已经放了i个传送门的方案数
那么我们可以枚举j位置上一个可以恰好踩到的位置j-k,其中j-k+1到j-1是放满了传送门的,所以这些位置时不可以踩到的,只能踩到j-k,那么这些放传送门的地方传送到哪里都是无所谓的,方案数就是一个连乘
那么只要由f[i-(k-1)][j-k]转移到f[i][j]就行了,初始状态f[0][j]=1,也就是完全不放传送门的方案数就是1种
由于我们最后要恰好到踩到n,且放了m个传送门,所以答案是f[m][n]
每次转移都从上一个可以踩的地方j-k转移过来,更远的地方如果也有可以转移到j的位置l,不用管它,因为l到j-k中间有没有放已经被l->j-k给转移过了,所以统计的方案数是正确的
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=1010;
const int mod=1e9+7;
int n,m,cas,k,cnt,tot;
int a[maxl],b[maxl];
ll dp[maxl][maxl],ans;
char s[maxl];
bool in[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
dp[i][j]=0;
}
inline void mainwork()
{
for(int j=1;j<=n;j++)
dp[0][j]=1;
ll tmp=1;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
tmp=1;
for(int k=1;k<=11;k++)
{
if(j-k<=0 || k-1>i)
break;
dp[i][j]=(dp[i][j]+dp[i-(k-1)][j-k]*tmp)%mod;
tmp=tmp*(j-k-1)%mod;
}
}
ans=-1;
if(dp[m][n]>0)
ans=dp[m][n];
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}