タイトル説明
で\(N×m個の\)行列の各列の各行は、ダイヤモンドを有する、ダイヤモンド分布の種類を尋ねますか?
答えはに大きな、出力答えがあるかもしれません\(十億七\)を法。
入力
各テストケースのために、二つの整数であり、\(N- \)と\(m個\)ボックスのサイズを表します。\(0 <N、M < 50 \)
出力
各データの出力分布の数。
サンプル入力
1 1
2 2
2 3
サンプル出力
1
7
25
これは、比較的良好な包含と除外の問題です。
まず、それは私たちが見ることは明らかである\(N、M \)範囲は考慮して、素晴らしいではありません\(DPを\) 。
定義\(DP [i]は[J ] \) 発現(I \)\行と\(J \)満たされている条件のプログラム番号の列。
そこにある理由については、\(私は\)ラインと\(J \)列ではなく、かつての\(私は\)ラインと\(J \)対応の前にあるため、列\(私は\)ライン、そこに\(I \)ラインは、より良い需要に簡単になります。
直接的および除外を求めた後にすることができます。
以下の定義で、私たちは直接精力的に開始することができます\(DP \) Aを。
現在検討のために\(Iは\)行\(J \)の合計ではない場合、列、ダイヤモンド確定考える\(2 ^ {iがjで* } \) のエミュレートされています。
そして今、我々はプログラムを削除する条件を満たしていないためにどの必要があります。
以下のために\(私は\)ライン\(J \)列、我々はより少ないを取り除くために必要がある\(私は\)ライン\(J \)の列、そして我々は(DP \)を\小規模から大規模な作品にあります引用しました。
だから、私たちが要求したとき(DP [I] [J \ ] \) する場合、\(DP [I-1]〜[J] ... \)など、\(DP \)私たちが求めている価値を。
そして\(Iは\)行\(J \)除去する方式列\(\)の線\(B \)プログラムはことはない\(Iは\)行\(J \)カラム選択\を( \)ライン\(のb \)列ますか?
行と列、すなわちより、カウントするように分離することができる\(Iは\)行\(J \)カラム選択\(\)ライン\(B \)から数スキームカラム= \(Iは\)選択された行(\ \) *からのプログラム行数\(J \)の列は、選択し\(B \)プログラムの列の数を。
それ\(C(I、A)* C(N-、J)\) 。
同様に、我々はすべてのより等しいかそれ以下に列挙\((i、j)を\ ) ポイントのが、これらの条件が満たされていないマイナスのプログラムだけで罰金。
負追加することに注意してくださいその後、モジュラスを法
コードは以下の通りです
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC target("avx,avx2,sse4.2")
#pragma GCC optimize(3)
inline int Read(void) {
int res=0,f=1;
char c;
while(c=getchar(),c<48||c>57)if(c=='-')f=0;
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48&&c<=57);
return f?res:-res;
}
template<class T>inline bool Min(T &a, T const&b) {
return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
return a<b?a=b,1:0;
}
const int N=55,M=1e5+5,mod=1e9+7;
bool MOP1;
int n,m,Fac[N],Inv[N],V[N],Pow[N*N],dp[N][N];
int C(int a,int b) {
return ((Fac[a]*Inv[a-b])%mod*Inv[b])%mod;
}
bool MOP2;
inline void _main(void) {
Fac[0]=Inv[0]=Fac[1]=V[1]=Inv[1]=Pow[0]=1ll;
rep(i,2,50) {
Fac[i]=(Fac[i-1]*i)%mod;
V[i]=(mod-mod/i)*V[mod%i]%mod;
Inv[i]=(Inv[i-1]*V[i])%mod;
}
rep(i,1,2500)Pow[i]=Pow[i-1]*2ll%mod;
rep(i,0,50)rep(j,0,50) {
dp[i][j]=Pow[i*j];
rep(a,0,i)rep(b,0,j) {
if(a==i&&b==j)continue;
dp[i][j]=(dp[i][j]-((dp[a][b]*C(i,a))%mod*C(j,b))%mod)%mod;
}
dp[i][j]=(dp[i][j]+mod)%mod;
}
while(~scanf("%lld %lld",&n,&m)) {
printf("%lld\n",dp[n][m]);
}
}
signed main() {
_main();
return 0;
}