NKOJ P4261 跳【组合数学】

这道题其实也不是很难……我考试的时候用了逆元求组合数然后数组就炸掉了……考试之后想了想我考试的时候推出来的公式其实是可以只计算一次的……

我们先考虑把表打出来 0,0>(5,5) ( 0 , 0 ) − > ( 5 , 5 )
1    1    1    1    1    1 1         1         1         1         1         1
1    2    3    4    5    6 1         2         3         4         5         6
1    3    6    10  15  21 1         3         6         10     15     21
1    4    10  20  35  56 1         4         10     20     35     56
1    5    15  35  70  126 1         5         15     35     70     126
1    6    21  56  126  252 1         6         21     56     126     252
观察一下规律我们发现第 n,m ( n , m ) 格的数字是 Cmn+m C n + m m
由于表是对称的,所以 (n,m)=(m,n) ( n , m ) = ( m , n ) ,不妨假设 n>m n > m
那么最后的答案:

Ans=n+C0n+0+C1n+1+C2n+2+...+Cmn+m A n s = n + C n + 0 0 + C n + 1 1 + C n + 2 2 + . . . + C n + m m

即:

Ans=n+0imCin+i A n s = n + ∑ 0 ≤ i ≤ m C n + i i

继续化简:

Ans=n+Cmn+m+1 A n s = n + C n + m + 1 m

所以最后的结果就出来了,那么现在无论用什么方法(只要不是暴力)都可以很快的求出这个答案了。

参考代码:

#include 
#include 
#include 
#include 
#include 
#define DB double
#define SG string
#define LL long long
using namespace std;
const LL Max=1e5+5;
const LL Mod=1e9+7;
const LL Inf=1e18;
LL N,M;
inline LL Read(){
    LL X=0;char CH=getchar();bool F=0;
    while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();}
    while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();}
    return F?-X:X;
}
inline void Write(LL X){
    if(X<0)X=-X,putchar('-');
    if(X>9)Write(X/10);
    putchar(X%10+48);
}
LL KSC(LL A,LL B,LL P){  
    A%=P,B%=P;  
    LL C=(long double)A*B/P;  
    LL Ans=A*B-C*P;  
    if(Ans<0){  
        Ans+=P;  
    } else if(Ans>=P) {  
        Ans-=P;  
    }return Ans;  
}  
LL KSM(LL A,LL B,LL C){  
    int Ans=1%C;  
    for(;B;B>>=1){  
        if(B&1){  
            Ans=KSC(Ans,A,C);  
        }A=KSC(A,A,C);  
    }return Ans;  
}  
LL C(LL A,LL B)  
{  
    if(Areturn 0;  
    if(A==B) return 1;  
    B=B>A-B?A-B:B;  
    LL GA=1ll,GB=1ll;  
    for(LL I=0;Ireturn (GA*KSM(GB,Mod-2,Mod))%Mod;  
}  
LL Lucas(LL N,LL M)  
{  
    if(M==0) return 1;  
    return C(N%Mod,M%Mod)*Lucas(N/Mod,M/Mod)%Mod;  
}
int main(){
    LL I,J,K;
    N=Read(),M=Read();
    Write((max(N,M)+Lucas(N+M+1,min(N,M)))%Mod);
    return 0;
}

你可能感兴趣的:(NKOJ,数学-组合数学)