visit:組合數學,ex_Lucas


沒做過ex_Lucas的同學可以先看看這個:組合數學專題《禮物》題解。順便把那道題水了。

強烈推薦tdcp的解,只用求2個組合數,考場打表,沒有為什么:666

有一個公式蠻重要的,竟然還有人不知道?

有一共n種共k個物品,每一種有a1,a2,a3...an個,它們本質不同的排列數是

$ \frac{k!}{a_1 ! \times a_2 ! \times a_3 ! \times ... \times a_n !}  (\sum\limits_{i=1}^n a_i =k) $

要解釋嘛?解釋一下吧。

首先對所有物品進行全排列,k!

而對於每一種物品,把它從這k個里提出來,其內部的順序被重復計算了

所以要除掉它內部的全排列,即ai!。

那么接下來我們來看着道題。

首先,我們可以發現,nm的正負對解題沒有影響,統一把它當作正的就好(向右,上為正方向)

那么如果我們一共向左走了a步,那么必須向右走n+a步,同理向下b步就要向上m+b步.(a,b,n-a,m-b均為自然數)

t=(a)+(n+a)+(b)+(m+b)=n+m+2a+2b

t-n-m=2a+2b=2(a+b)

所以說,如果t-n-m為奇數或負數,方案數為0。

在這個式子里面我們未知的只有a和b。枚舉其一就能得到另一個。

假如我們現在已經確定了一對a,b,如何求解方案數?

我們有a左(n+a)右b下(m+b)上,我們現在要求這些操作的排列數。

根據我開頭說的那個式子,就挺好寫出算式了:(開頭那個式子記住吧,挺重要的)

$ \frac{t !}{a !\times b! \times (n+a)! \times (m+b)!} $

接下來的問題是如何計算。。。

對於60%的數據,p是一個質數,簡單啊,直接Lucas或階乘逆元硬干就好了啊

(如果你連朴素Lucas都不知道,那我救不了你了)

但是對於全部數據,p可以是一個合數。。。就是禮物那道題了。

分解p得到若干質數,對於這些質數取模分別求解。

在求解對於某一個分解后的質數取模時,套一個朴素Lucas即可。

最后一個CRT合並答案。

---接下來你可以選擇不看---

然而我打的十分麻煩。。。我並沒有發現需要ex_Lucas和普通Lucas。我以為直接CRT就可以。

然而40分。懵了一陣。

仔細一看發現,因為它有小質數所以會爆炸。

如果要計算$1 \times 3 \div 3 (mod 3)$,那么我會先算1×3=3,取模變成0,在除以3還是0。

呃。。。什么玩意啊!

后來一想,它不就像ex_Lucas一樣嗎?只要分離記錄那個質數的次數不就好了嗎?

然后我就暴力計算指數的次數,暴力算階乘。

那么在上式枚舉的過程中,a每增大1,組合數怎么計算?

我很“機智”的想到了,這不和划艇那題的組合數遞推挺像嗎?(錯誤的“做題長記性”)

既然a是枚舉的,每當a增大1,那個式子只需要除a再除n+a再乘b+1再乘m+b+1不就好了嗎?

乘除不能直接乘除,要把分解后的質數提出來。完事!

完美。

完美?

對,對,對是對了,運行倒數第二,碼長也十分驚人。

但是因為沒有預處理階乘和逆元,少開了不少數組,內存492k倒是最小的。

思維量挺大,理論上是好事,可是在考場上。。。

不建議按我這個思路打,但是你們可以順着我的思路想一想,萬一用上了呢?

好了,就這樣吧,有什么不懂的去評論區噴我就行,看到就回復。

這題講的有點草率,因為要去寫T3的題解。

哦對了,還有,因為我的思路清奇,所以代碼還是去頹別人的吧。

 1 #include<cstdio>
 2 #define int long long
 3 #define orz mod[modi]
 4 int Mod,mod[11],mods,t,n,m,ans[11],Ans,x,y;
 5 int pow(int b,int mod,int ans=1){
 6     for(int t=mod-2;t;t>>=1,b=b*b%mod) if(t&1) ans=ans*b%mod;
 7     return ans;
 8 }
 9 void exgcd(int a,int b,int &x,int &y){
10     if(!b){x=1;y=0;return;}
11     exgcd(b,a%b,x,y);
12     int res=x;x=y;y=res-a/b*x;
13 }
14 signed main(){
15     scanf("%lld%lld%lld%lld",&t,&Mod,&n,&m);
16     if(n<0)n=-n; if(m<0)m=-m;
17     if(t<n+m){puts("0");return 0;}
18     if(t-n-m&1){puts("0");return 0;}
19     for(int mm=Mod,i=2;i<=100000;++i)
20         if(mm%i==0)mod[++mods]=i,mm/=i;
21         else if(i==100000&&mm!=1)mod[++mods]=mm;
22     for(int modi=1;modi<=mods;++modi){
23         int na=n,a=0,mb=m+(t-n-m)/2,b=(t-n-m)/2,C=1,tms=0;
24         for(int i=1;i<=t;++i){
25             int res=i;
26             while(res%orz==0)tms++,res/=orz;
27             C=C*res%orz;
28         }//printf("-%lld %lld\n",C,tms);
29         for(int i=1;i<=na;++i){
30             int res=i;
31             while(res%orz==0)tms--,res/=orz;
32             C=C*pow(res,orz)%orz;
33         }//printf("--%lld %lld\n",C,tms);
34         for(int i=1;i<=mb;++i){
35             int res=i;
36             while(res%orz==0)tms--,res/=orz;
37             C=C*pow(res,orz)%orz;
38         }//printf("---%lld %lld\n",C,tms);
39         for(int i=1;i<=b;++i){
40             int res=i;
41             while(res%orz==0)tms--,res/=orz;
42             C=C*pow(res,orz)%orz;
43         }//printf("----%lld %lld\n",C,tms);
44         ans[modi]=(ans[modi]+(tms?0:C))%orz;
45         while(b){
46             b--;mb--;a++;na++;int res;
47             res=b+1;while(res%orz==0)tms++,res/=orz;C=C*res%orz;
48             res=mb+1;while(res%orz==0)tms++,res/=orz;C=C*res%orz;
49             res=a;while(res%orz==0)tms--,res/=orz;C=C*pow(res,orz)%orz;
50             res=na;while(res%orz==0)tms--,res/=orz;C=C*pow(res,orz)%orz;
51             (ans[modi]+=(tms?0:C))%=orz;//printf("-----%lld %lld\n",C,tms);
52         }
53         exgcd(Mod/orz,orz,x,y); x*=ans[modi]; x=(x%orz+orz)%orz;
54         (Ans+=Mod/orz*x%Mod)%=Mod;
55     }
56     //for(int i=1;i<=mods;++i)printf("%lld %lld\n",mod[i],ans[i]);
57     printf("%lld\n",Ans);
58 }
形式化地放着


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM