問題点S:グリッドVI
制限時間:1秒 メモリ制限:128メガバイトの提出:8 分解能:4
[ 提出 ] [ 状態 ] [命題男性:ADMIN ]
タイトル説明
都市街路グリッド状は、左下隅の位置座標(0、0)、(n、m)がBの右上、N> = Mの座標。今、図の(0、0)の点から、又はばかり通りに沿って歩いてではなく、左上に示す点を通る直線は、すなわち、点の任意の経路(x、y)が満たさなければならないフロント真上X> = Y、ウィルこれらの施設、到着B(n、m)がどのように多く移動します。
エントリー
二つの整数nとmを含む唯一のラインは、都市ブロックのサイズを表します。
輸出
唯一の全体数とラインフィード/キャリッジリターンは、異なる方式の総数を表します。
サンプル入力
6 6
サンプル出力
132
プロンプト
データの100%、1 <= M <= N <= 5 000
以下のように数学的なトピックの組み合わせは、式が導出されます。
この質問高精度かつ高精度乗算分裂を必要とすることは明らかであるが、私は怠け者だと高精度の分裂を書きたくないので、素因数分解法の思想ので、除算はインデックスに高精度の減算素因数に変換されますやります。
だから、唯一、答えはに対処するために出てくるとき、最後の答えに高精度の乗算処理を使用する必要が測定され、平均高精度の分割処理よりもはるかに高速、非常に高速に実行されています。
次のようにACコードは
#include <bits/stdc++.h> #define rint register int typedef long long ll; using namespace std; const int N=5e3; const int mod=1e8; struct bign { ll val[1000]; int len; bign() { memset(val,0,sizeof val); } bign operator *(const bign &t)const { bign res; for(rint i=0; i<len; i++) for(rint j=0; j<t.len; j++) { res.val[i+j]+=val[i]*t.val[j]; res.val[i+j+1]+=res.val[i+j]/mod; res.val[i+j]%=mod; } res.len=len+t.len; if(res.val[res.len-1]==0)res.len--; return res; } }; bign transbign(ll x) { int j=0; bign res; while(x) { res.val[j++]=x; x/=mod; } res.len=j; return res; } void write(bign x) { int i=x.len; printf("%lld",x.val[--i]); while(i)printf("%08lld",x.val[--i]); puts(""); } int prime[2*N+5],cnt; bool vis[2*N+5]; void erla() { for(int i=2; i<=2*N; i++) { if(!vis[i])prime[++cnt]=i; for(int j=1; j<=cnt&&prime[j]*i<=2*N; j++) { vis[i*prime[j]]=true; if(i%prime[j]==0)break; } } } bign qpow(bign a,ll b) { bign ans; ans.val[0]=1;ans.len=1; while(b) { if(b&1)ans=ans*a; a=a*a; b>>=1; } return ans; } int up[N*2],down[N*2]; bign ans; int main() { ios::sync_with_stdio(false); cin.tie(0); erla(); int n,m; cin>>n>>m; for(int i=n+2; i<=n+m; i++) { int k=i; for(int j=1; j<=cnt&&prime[j]<=k; j++) { int p=prime[j]; while(k%p==0) { up[p]++; k/=p; } } } int k=n-m+1; for(int j=1; j<=cnt&&prime[j]<=k; j++) { int p=prime[j]; while(k%p==0) { up[p]++; k/=p; } } for(int i=2; i<=m; i++) { int k=i; for(int j=1; j<=cnt&&prime[j]<=k; j++) { int p=prime[j]; while(k%p==0) { down[p]++; k/=p; } } } bign t; ans.val[0]=1;ans.len=1; for(int i=1;i<=cnt;i++) { int p=prime[i]; int c=up[p]-down[p]; if(c==0)continue; //COUT << P << " "<<アップ[P] <<"" <<ダウン[P] << ENDL。 T = transbign(P)。 T = qpow(T、C)。 ANS = ANS *のトン。 } // COUT << ans.len << ENDL。 (ANS)を書きます。 リターン 0 ; }