2016暑期集训2-J
HDU 5698 瞬间移动(百度之星2016)
想法+组合取模
题意
中文的,有图,开源网页吧。
思路
m行n列,每次至少往右走一步、往下走一步,所以一共往右走n-1格,往下走m-1格。所以最多走min(m-1,n-1)次。往右走往下走的次数相等,所以把m-1和n-1分别拆成k个数的和。k从1取到min(m-1,n-1)。拆数用隔板法组合。求出走k次的方法数,然后加起来就可以了。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<iomanip>
using namespace std;
const int MAXN = 100007;
const int oo = 2000000007;
const long long int loo = 1000000000000000007ll;
const int MOD = 1000000007;
typedef long double ld;
typedef long long ll;
ll fact [ MAXN ];
ll f [ MAXN ];
ll inv [ MAXN ];
ll CMOD ( ll a , ll b )
{
b = min ( b , a - b );
ll res = 1;
res = res*fact [ a ];
res %= MOD;
res = res*inv [ a - b ];
res %= MOD;
res = res*inv [ b ];
res %= MOD;
return res;
}
int main ( )
{
int m , n;
memset ( fact , 0 , sizeof ( fact ) );
memset ( f , 0 , sizeof ( f ) );
memset ( inv , 0 , sizeof ( inv ) );
fact [ 0 ] = 1;
f [ 0 ] = 1;
inv [ 0 ] = 1;
fact [ 1 ] = 1;
f [ 1 ] = 1;
inv [ 1 ] = 1;
for ( int i = 2; i < MAXN; i++ )
{
fact [ i ] = ( fact [ i - 1 ] * i ) % MOD;
f [ i ] = ( MOD - MOD / i )*f [ MOD%i ] % MOD;
inv [ i ] = inv [ i - 1 ] * f [ i ] % MOD;
}
while ( scanf ( "%d%d" , &n , &m ) == 2 )
{
n--;
m--;
ll res = 0;
for ( int i = 1; i <= min ( m , n ); i++ )
{
res += ( CMOD ( m - 1 , i - 1 ) * CMOD ( n - 1 , i - 1 ) );
res %= MOD;
}
printf ( "%I64d\n" , res );
}
return 0;
}