BZOJ3907グリッド

猫は、この事は数学の組み合わせを取るためになされたと思いました。

この必要性は、最初の猫$ C_ {2N} ^ n型C_ {2N} ^ {N-1} $解析を行いますラインまたはグリッドの方法を折るする方法です。

グリッド法:制限はないが、(0,0)からのプログラムの数(N、N)に$ C_ {2N} ^ N $は、2n個の操作位置(上右又は)の合計である、我々は我慢これらの操作は、上記の式に挿入された位置をとり、黄色の線は、我々が不法に遭遇するようになって最初の行の上で、我々は最終的には、この時点で(N、N)に来る我々なら長方形は、我々は黄色の線が発生し、この線に沿って折り畳まれ、その後、(N、n)と散歩に行ってきました、あなたは黄色の線に触れマッピングされ、その後に行ってきました(N-1、N + 1)と散歩することができます対称なもののため。

黄色の線は違法なスキームの数は(0,0)からに行ってきました(N-1、N + 1というように、影響を受けません折りたたみ行列に移動する前に、私たちは会った ) 、これをプログラムの数をほとんど分析上、$ C_の合計{2N} ^ {N -1} $ 種マイナスすべての違法、合法である、$ {C_-C_ 2N} ^ {N-2N-N-} ^ {}。1 $

行を折る:つまり、(0,0)からのみに沿って(2N、0)、各時間に対して、Y = xまたはy =、画像全体がXの下方に位置する最後のプログラム番号部分ではない1つの単位ダウン-x。限定するものではないが、その後のためのプログラムの合計数$ C_ {2N ^ N} $は、2n個のセグメントに分割することができる行を折り返すため、そこn個片が上昇、n段落ちます。=このラインyの最初の出会いから、x軸と交差することはできません-1 =正当開始されず、この点の後、我々は、Yを有する-1折り線に沿って折り曲げ、最後の到着(2N、0)の点から、合計到達した後(2Nを、-2)、(2N -2)プログラムの数にケース(0,0)に変換されるオフ、+ 1つのセグメントは、プログラムがダウンn段は、N-1までの期間、n個番号$} ^ {C_ {2N-N- $}。1不法全てマイナスは、合法的である$ {C_-C_ 2N} ^ {N-2N-N-} ^ {} $ 1

この質問は、上記のように上記と同様の方法により、はるかに単純であること、同じ被写体上にn mを交換します

答案就是$C_{n+m}^n-C_{n+m}^{m-1}$,下面的代码是化简后的式子,没有高精减,高精除用唯一分解刚过去,而且时间复杂度也还好,就打的n√n的拆分,nlogn的拆分在下一篇博客里,(因为那个题√n拆过不去QAQ)。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
int n,m;
int prime[5000],prime_num;
bool v[10050];
int fz[5000],fm[5000];
struct Bigint{
    int a[90000],len;
    void clear(){
        memset(a,0,sizeof(a));
        a[1]=1;
        len=1;
    }
    friend void operator * (Bigint &x,int y){
        int delta=0;
        for(int i=1;i<=x.len;i++){
            x.a[i]=x.a[i]*y+delta;
            delta=x.a[i]/10;
            x.a[i]%=10;
        }
        while(delta>0){
            x.a[++x.len]=delta%10;
            delta/=10;
        }
        while(x.a[x.len]==0&&x.len>1)
            x.len--;
    }
    void out(){
        for(int i=len;i>=1;i--)
            printf("%d",a[i]);
    }
}ans;
void doprime(){
    for(int i=2;i<=10005;i++){
        if(!v[i]) prime[++prime_num]=i;
        for(int j=1;j<=prime_num&&i*prime[j]<=10005;j++){
            v[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
void mulfz(int x){
    for(int i=1;i<=prime_num;i++)
        while(x%prime[i]==0){
            fz[i]++;
            x/=prime[i];
        }
}
void mulfm(int x){
    for(int i=1;i<=prime_num;i++)
        while(x%prime[i]==0){
            fm[i]++;
            x/=prime[i];
        }
}
int main(){
    scanf("%d%d",&n,&m);
    doprime();ans.clear();
    for(int i=2;i<=n+m;i++)
        mulfz(i);
    mulfz(n-m+1);
    for(int i=2;i<=m;i++)
        mulfm(i);
    for(int i=2;i<=n+1;i++)
        mulfm(i);
    /*for(int i=1;i<=prime_num;i++)
        cout<<prime[i]<<" ";cout<<endl;*/
    for(int i=1;i<=prime_num;i++){
        for(int j=1;j<=fz[i]-fm[i];j++)
            ans*prime[i];
    }
    ans.out();
    puts("");
    return 0;
}
View Code

 

おすすめ

転載: www.cnblogs.com/Yu-shi/p/11222174.html