1. 程式人生 > 實用技巧 >Codeforces Round #663 (Div. 2) C. Cyclic Permutations

Codeforces Round #663 (Div. 2) C. Cyclic Permutations

題目連結:https://codeforc.es/contest/1391/problem/C

題意:每個數會和左邊最近的大於他的數的下標連線一條無向邊,和左右最近的大於他的數的下標也連線一條,問該排列有環的情況有多少種

思路:模擬一下就很容易發現,只要有2 1 3 某個數左右兩邊都有一個數大於他,就至少存在一個三元環

那麼難點就在於如何求出這些情況, 要麼正面求要麼反面求,正面求沒有求出來,感覺很難處理,反面求的話就是n!減去無環的情況

其實觀察4的樣例 猜測一下 就能猜得到答案n!-2^(n-1) 這種組合數多數和2的幾次方有關係的

如果求的話, 就是一個數一個數的放, 1的話只有一種情況, 2的話可以放1的左右兩邊2種情況,3的話只能放2的左右兩邊如果放其他位置都會產生上述情況產生環

每個數只能放上一個數的左右兩邊,共n-1個數可選,所以是2^(n-1)。

另外一種考慮方法, 就是能看出來只有先遞增後遞減 或者單增單減這種情況才滿足條件

那麼我們考慮以最大的n為中心,列舉左邊有多少個數即可, 枚舉了左邊有多少個數,剩下的數都在右邊,因為右邊都是遞減,所以右邊的就確定下來了

所以是累加C(i,n-1) i從0到n-1 累加後也就是排列組合的二項式係數的公式 =2^(n-1)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5
const int maxn =1e5+10; 6 const int mod=1e9+7; 7 8 9 ll power(ll base,ll n) 10 { 11 ll r=1; 12 while(n) 13 { 14 if(n%2) r=r*base%mod; 15 base=base*base%mod; 16 n/=2; 17 } 18 return r; 19 } 20 21 22 int main() 23 { 24 ios::sync_with_stdio(false); 25
cin.tie(0); 26 ll n; 27 cin>>n; 28 ll temp=1; 29 for(int i=1;i<=n;i++) 30 temp=temp*i%mod; 31 ll ans=temp-power(2,n-1); 32 ans=(ans+mod)%mod; 33 cout<<ans<<'\n'; 34 35 36 37 38 39 }
View Code