2018牛客多校赛第一场 A Monotonic Matrix(组合计数)

版权声明:本文为博主原创文章,转载请著名出处 http://blog.csdn.net/u013534123 https://blog.csdn.net/u013534123/article/details/82792312

大致题意:给你一个n*m的矩阵,每一个位置可以填0、1和2三个数字,但是要求每个数字下面和右边的数字要大于等于他自己。现在问满足条件的填数字方法有多少种。

看完这道题,很明显的一个dp题。转移方程也很容易想出来,但是这样写出来你会发现样例也过不了-_-。

其实问题也很明显,这个问题不满足后效性,计算出来的方案数会比实际的方案数要多。那么我们就得换一个思路去思考这个问题。注意到,任意一种可行的方案,我们基本上可以找出两条分界线,01分界线和12分界线。而且可以看到,这两条分界线也是不可相交的,但是可以重合的。于是,我们可以把问题变成从左下角走到右上角,找两条不相交但可以重合的路径条数。

对于这个问题,我们有一个定理:求下面矩阵的行列式,其中 e(a,b) 是表示从点a到点b的方法数,带入求行列式即可得到(a1,a2,...an) 到 (b1,b2,...bn) 的所有不相交路径的种数

这个定理适用于不相交的情况,也即不能有重合。但是本题可以重合,所以我们不妨把其中一条路径平移一下。即原本是从点(n,0)到(0,m)的两条路,改成从点(n-1,0)到(-1,m)和点(n,0)到(0,m)的两条路。然后带入公式求解即可,最后的答案:

                            

具体间代码:

#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double PI = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> P;
LL qpow(LL a,LL b){
    LL ans = 1;
    a %= mod;
    while( b > 0){
        if(b&1) ans = ans*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return ans;
}
const int maxn = 2e3+100;
LL fac[maxn],invfac[maxn];
void init(void){
    fac[0] = 1;
    invfac[0] = 1;
    for(int i = 1;i < maxn; ++i)
       fac[i] = fac[i-1]*i%mod,invfac[i] = qpow(fac[i],mod-2);    
}
int main(void)
{
   init();
   LL n,m;
   while(scanf("%lld %lld",&n,&m) != EOF){
         LL ans = (fac[m+n]*invfac[m]%mod*invfac[n]%mod);
         ans = ans*ans%mod;
         ans = ans - fac[m+n]*fac[m+n]%mod*invfac[n+1]%mod*invfac[n-1]%mod * invfac[m+1]%mod * invfac[m-1]%mod;
         ans = (ans%mod + mod)%mod;
         printf("%lld\n",ans);
   }     
 
   return 0;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/82792312
今日推荐