日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Zjoi2010排列计数Perm

發布時間:2025/3/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Zjoi2010排列计数Perm 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這東西還是挺有思想的,道聽途說一些東西,問問DuanYue同志,然后自己打表畫樹推了推,就搞出來了。

首先根據p i>p i/2(向下取整)這種形式,如果線段樹學的好的人,一定能看出來,這是在唯一標號法標號后的形式,即父親的權值大于兩個兒子的權值,這是一個小根堆的樣子。

那問題就是求給定數目的數字,求其能構成小根堆的個數。

這是一個類似樹形dp的問題,我們設f[i]表示以當前節點為根所能構成小根堆的個數,那么有狀態轉移方程:

就是說當前節點及其子樹一共分配了size[i]個數字,然后分給了左右子樹,有上式Combine種可能,然后把左右兒子的貢獻轉移上來。

組合數還是老規矩打階乘及其逆元的表,用lucas定理求一下,因為不用的話模數小的時候會崩,模數大了lucas也可以自動求組合取模。

實現過程中沒有定義dp數組(其實size數組也沒必要),直接帶返回值的dfs搞一下。

代碼略丑,勿看(主要是懶,直接define int long long 了)。

#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<vector> #include<queue> #define int long long using namespace std; int n,p; int size[2000000]; int fac[2000000],inv[2000000]; int qpow(int x,int k){int ans=1;for(;k;k>>=1,x=1ll*x*x%p)if(k&1) ans=1ll*ans*x%p;return ans; } void pre(){fac[0]=1;for(int i=1;i<min(n,p);i++)fac[i]=1ll*fac[i-1]*i%p;inv[min(n,p)-1]=qpow(fac[min(n,p)-1],p-2);for(int i=min(n,p)-1;i>=1;i--)inv[i-1]=1ll*inv[i]*i%p; } int com(int x,int y){if(y>x) return 0;return ((1ll*fac[x]*inv[y])%p*inv[x-y]%p)%p; } int lucas(int x,int y){if(!y) return 1;return com(x%p,y%p)*lucas(x/p,y/p)%p; } int dfs(int x){if(x>n) return 1;size[x]++;int a=dfs(x<<1)%p;int b=dfs(x<<1|1)%p;size[x]+=size[x<<1]+size[x<<1|1];return 1ll*((a*b)%p*(lucas(size[x]-1,size[x<<1])%p))%p; } signed main(){scanf("%lld%lld",&n,&p);pre();/*for(int i=1;i<=p;i++)cout<<fac[i]<<" ";cout<<endl;for(int i=1;i<=p;i++)cout<<inv[i]<<" ";cout<<endl;*/printf("%lld",dfs(1)%p);return 0; } View Code

?

轉載于:https://www.cnblogs.com/Yu-shi/p/11121778.html

總結

以上是生活随笔為你收集整理的Zjoi2010排列计数Perm的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。