1. 程式人生 > >汕頭市隊賽SRM 20 T3 靈魂覺醒

汕頭市隊賽SRM 20 T3 靈魂覺醒

精確 它的 i++ aps 排好序 string 算法 希望 表示

背景

自從芽衣、布洛妮婭相繼靈魂覺醒之後,琪亞娜坐不住了。自己可是第一個入駐休伯利安號的啊!於是她打算去找德麗莎幫忙,為她安排了靈魂覺醒的相關課程。

第一天,第一節課。

“實現靈魂覺醒之前,你需要先將自己的崩壞能按順序排好……”

“誒誒,這個要怎麽做呢?”算法課沒認真聽講也是沒有辦法的嘛。

於是,琪亞娜設(xia)計(bian)了一套自己的排序方法。

描述

我們可以用n張卡片代表崩壞能,上面恰好寫了1到n。

一開始這些卡片是隨機排列的,然後為了把它們從小到大排好序,進行如下操作:

①如果卡片已經按1到n排好序,結束操作。

②觀察現有排列,如果某一個大於1的區間內的數是順序加一的,就把這個區間內的卡片粘起來,它們在以後的操作中不會分開。(比如15234這個排列會把234粘起來)

③把所有卡片隨機排列(粘在一起的不分開),然後回到①。

恰好路過的符華對這種排序方法非常感興趣,希望知道它的期望復雜度。於是求期望進行③操作的次數的任務就交給你了。答案對1e9+7取模。

輸入格式

一個不超過2000的整數n。

輸出格式

一個整數,答案對1e9+7取模後的結果。

樣例輸入

3

樣例輸出

333333338

數據範圍與約定

測試點 n
1
1
2 5
3 8
4 10
5 13
6 <=1000
7 <=1000
8 <=2000
9 <=2000
10 <=2000

樣例解釋

n=3時的精確值是技術分享

後記:

琪亞娜·卡斯蘭娜:你們是怎麽排序的啊?

雷電芽衣:有個庫函數叫sort來著……

布洛妮婭:對,挺快的。

————————————————————————————

這題一開始我想著暴力 ans[x]=sigma g[x][y]*ans[y]

g[x][y]表示長度為x的排列 排一次之後縮成y段的概率

g[x][y]可以暴力算 不過後來打表發現是個組合數 然後就可以A辣

技術分享
#include<cstdio>
#include
<cstring> #include<algorithm> #define LL long long const int M=2e3+7,mod=1e9+7; int read(){ int ans=0,f=1,c=getchar(); while(c<0||c>9){if(c==-) f=-1; c=getchar();} while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();} return ans*f; } int n,k; int g[M][M]; LL w[M],inv[M]; LL pmod(LL a,LL b){ int ans=1; while(b){ if(b&1) ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans; } void prepare(){ w[0]=1; for(int i=1;i<=n;i++) w[i]=w[i-1]*i%mod; inv[n]=pmod(w[n],mod-2); for(int i=n;i;i--) inv[i-1]=inv[i]*i%mod; } int f[M],v[M],s[M],ans[M]; void P(int &x){x=(x%mod+mod)%mod;} int main(){ n=read(); prepare(); for(int j=1;j<=n;j++){ g[j][j]=w[j]-s[j]; P(g[j][j]); for(int i=j+1;i<=n;i++){ g[i][j]=g[j][j]*(w[i-1]*inv[j-1]%mod*inv[i-j]%mod)%mod; P(g[i][j]); s[i]+=g[i][j]; P(s[i]); } } ans[1]=0; for(int i=2;i<=n;i++){ LL ly=0; for(int j=2;j<i;j++) ly=(ly+1LL*g[i][j]*inv[i]%mod*(ans[j]+1)%mod)%mod; ans[i]=((ly+g[i][i]*inv[i]%mod)*pmod((1-g[i][i]*inv[i]%mod+mod)%mod,mod-2))%mod; }printf("%d\n",ans[n]); return 0; }
View Code

汕頭市隊賽SRM 20 T3 靈魂覺醒