題意:
給定一個圓,圓上有?n=2023?個點從?1?到?n?依次編號。
問有多少種不同的連線方式,使得完全沒有連線相交。當兩個方案連線的數量不同或任何一個點連接的點在另一個方案中編號不同時,兩個方案視為不同。
答案可能很大,請將答案對?2023?求余后提交。
思路:
首先是卡特蘭數,然后沒了,G32 卡特蘭數_嗶哩嗶哩_bilibili,如果不理解,可以看這個視頻,這道題其實就是視頻中的拓展,加了個組合數選多少個點而已。
理解:? ? 首先這個理解很可能有問題,如果你有更好的想法,請一定要在評論里告訴我,因為我現在都還是不太確定我的理解是否正確。
我看了很多關于卡特蘭數的,看完之后感覺都像是感覺,沒有一個確切的說怎么怎么樣就是卡特蘭數,因此我目前把卡特蘭數歸納為
一個問題在任何子集情況下,違規操作的條件是不變動的,執行違規操作后,無論后面是什么樣的,一定是錯誤,那么就是卡特蘭數的使用范疇。
例如這道選點,違規操作就是不能選擇穿越區間的點,無論你進行到哪一步怎么劃分都是這個條件,即不能穿過上一條線選點。
如果是出入棧問題,那么無論你進行了多少步,只要出棧操作次數超過入棧那么就是錯誤,無論在哪個子集,哪一步,都是這個條件。
如果是二叉樹,無論進行到哪一步,都不能連接已經連接過的點,這就是違規操作。
如果是連接頂點,無論到哪一步,都必須在選好一個節點去連新的邊,只要不符合這個要求,就會錯。
如果是斜線問題,無論到那一步,目前移動到的點不能超過斜邊。
無論在哪個自己情況下,條件不能發生變動,他是固定的。不需要分情況討論,無論在什么情況下都是一個要求,那就會是卡特蘭數。
判斷方式就是一道題的成功構造,是不是被一個固定條件限制住了,如果限制住,那很可能是卡特蘭數。
請注意:該方法完全是類似于數學歸納法,看了一些之后自己想出來的一個方式,本人完全想不出數學或者說正經的方式,而網上大抵也沒找到幾個嚴格指出的,都是感覺,或者類比,但是本人思維理解不了是怎么歸到一類的。比如這個圓圈選點跟斜線,我看不出相同點,所以自己思考歸納出來的這個相同點。非常不嚴格,請不要沿用這個方式。
說出這個歸納僅僅是希望后來有能力的人看到后,請來指正我,告訴我到底應該怎么思考更正確。
有參考:
1.題解:P10413 [藍橋杯 2023 國 A] 圓上的連線 - 洛谷專欄
2.「算法入門筆記」卡特蘭數 - 知乎
個人認為2的想法非常好,很有說服力,但是我認為這個圓上選點,我很難聯系到這個+1,-1,所以引出了這個自己的思考方法,其實跟+1,-1也挺像的……我只是覺得那個圓圈選點歸納到選棧真的有點異想天開的趕腳,有一點強行……
那么回到代碼,非常簡單,預處理組合數和卡特蘭數,卡特蘭數是一個遞推公式,至于怎么推導出來的……我也不會。
組合數預處理方式是帕斯卡法則,這里順帶推薦一下用到這個性質的好題【補題】Codeforces Global Round 21 E. Placing Jinas-CSDN博客
組合數的累加、楊輝三角就可以往這個方向思考
代碼:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define int128 __int128
#define endl '\n'
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 2e5+10;
const int INF = 1e18;
const int MOD = 2023;int C[2025][2025];
int H[2025];void solve(){int n=2023;for(int i=0;i<=2023;i++) C[i][0]=C[i][i]=1;for(int i=0;i<=2023;i++){for(int j=1;j<=i;j++){C[i][j]=(C[i-1][j]+C[i-1][j-1])%2023;}}H[0]=H[1]=1;for(int i=2;i<=2023;i++){for(int j=0;j<i;j++){H[i]=(H[i]+(H[j]*H[i-j-1]+MOD)%MOD)%MOD;}}int res=0;for(int i=0;i<=2023;i+=2){res=(res+(C[2023][i]*H[i/2]%MOD))%MOD;}cout << (res+MOD)%MOD << endl;
}signed main(){IOS;int t=1;
// cin >> t;while(t--){solve();}
}