[SLYZ] Arena | 一類斯特林數
這個題據說是 OIBH 上面的,但網站大概已經不在了,網上也找不到這道題了,但這是一道好題,我就來寫一份題解吧。
問題描述(1s 65536KB)
近日,CWTV 網絡電視公司為了提高收視率,舉辦了一場 CWTV 拳擊擂臺賽。
一共有 n 名選手參賽,分別為A1,A2……An。拳擊賽的舉辦者對每名參賽選手的實力作了詳盡的分析,發現若 Ai 能擊敗 Aj,則一定有 Ai > Aj。
現在舉辦者需要制定一個出場次序,第一個出場的作為第一任擂主,然後其他選手依次出場向擂主挑戰,凡是挑戰者戰勝了擂主,那麽這個挑戰者就頂替原擂主的位置成為新的擂主。
由於舉辦者希望比賽盡量的精彩,他希望在整
個擂臺賽中一共更換 k 次擂主。請你幫助他算出滿足他的要求的出場次序的個數。例如:出場順序 14253 說明了擂主依次是 1,4,5,這符合 n=5 和 k=2。
輸入格式
共一行:n,k。n 為參賽人數,k 為更換擂主次數。
規模:0<n<=500,0<=k<n。
輸入格式
出場次序的個數。
輸入樣例1
2 0
輸出樣例1
1
輸入樣例2
3 1
輸出樣例2
3
樣例說明
n=2, k=0 有唯一的出場順序 2 1
n=3, k=1 有出場順序 1 3 2; 2 3 1; 2 1 3
這題有點難想,打表也許能看出是一類斯特林數。
分析:
更換 k 次擂主,即有 k+1 個擂主,設 m=k+1。
將 n 個人分成 m 組,使每組裏有一個擂主,也就是每組裏面的最大值,使它排在該組的最前面,
在這一組裏,擂主後面的參賽者可以任意排列,因此,每組相當於一個圓排列,這 m 組也就是 m 個圓排列。
這 m 個圓排列間的順序是無所謂的,為了使後面的擂主替換前面的擂主,不妨使這 m 個圓排列按照它們的擂主大小升序排列。
若新添一個元素,此元素必為 n 個元素中最大的一個,可以使其單獨一個圓排列,放到最後;
也可以把它放到前 n-1 個元素任意一個元素的左邊,並替換掉這個圓排列裏的擂主,然後把該圓排列挪到最後。
也就轉換成一類 Stirling 數的圓桌問題了。
而 Stirling 數在 100 以內就會爆 long long,這題 n <= 500,顯然要用高精度。
測試數據已上傳到鏈接: https://pan.baidu.com/s/1pM0N6Oj 密碼: ai2m。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<string> 5 #include<string.h> 6 #include<vector> 7 using namespace std; 8 9 struct BigInteger{ 10 static const int BASE = 100000000; 11 static const int WIDTH = 8; 12 vector<int> s; 13 14 BigInteger(long long num = 0){ *this = num; } 15 BigInteger operator = (long long num){ 16 s.clear(); 17 do{ 18 s.push_back(num % BASE); 19 num /= BASE; 20 } while (num > 0); 21 return *this; 22 } 23 BigInteger operator = (const string &str){ 24 s.clear(); 25 int x, len = (str.length() - 1) / WIDTH + 1; 26 for (int i=0; i<len; i++) 27 { 28 int end = str.length() - i * WIDTH; 29 int start = max(0, end - WIDTH); 30 sscanf(str.substr(start, end - start).c_str(), "%d", &x); 31 s.push_back(x); 32 } 33 return *this; 34 } 35 BigInteger operator + (const BigInteger &b) const{ 36 BigInteger c, d; 37 c.s.clear(); 38 for (int i = 0, g = 0;; i++) 39 { 40 if (g == 0 && i >= s.size() && i >= b.s.size()) break; 41 int x = g; 42 if (i < s.size()) x += s[i]; 43 if (i < b.s.size()) x += b.s[i]; 44 c.s.push_back(x % BASE); 45 g = x / BASE; 46 } 47 return c; 48 } 49 BigInteger operator * (const long long &b) const{ 50 BigInteger c; 51 c.s.clear(); 52 for(int i = 0,g = 0;; i++) 53 { 54 if(g == 0 && i >= s.size()) break; 55 long long x = 0; 56 if(i < s.size()) x = s[i]*b; 57 x += g; 58 c.s.push_back(x % BASE); 59 g = x / BASE; 60 } 61 return c; 62 } 63 BigInteger operator *= (const long long &b){ 64 *this = *this * b; 65 return *this; 66 } 67 }; 68 ostream &operator<<(ostream &out, const BigInteger &x) 69 { 70 out << x.s.back(); 71 for (int i = x.s.size() - 2; i >= 0; i--) 72 { 73 char buf[20]; 74 sprintf(buf, "%08d", x.s[i]); 75 for (int j = 0; j < strlen(buf); j++) 76 out << buf[j]; 77 } 78 return out; 79 } 80 istream &operator>>(istream &in, BigInteger &x) 81 { 82 string s; 83 if (!(in >> s)) 84 return in; 85 x = s; 86 return in; 87 } 88 89 BigInteger f[2][510]; 90 91 int main() 92 { 93 freopen("c.in","r",stdin); 94 freopen("c.out","w",stdout); 95 96 ios::sync_with_stdio(false); 97 int n,k; 98 cin>>n>>k; 99 BigInteger t=1; 100 f[1][0]=1; 101 for(int i=2;i<=n;++i) 102 { 103 int x=max(0,k-n+i-1),y=min(k,i-2); 104 if(x==0) f[i&1][0]=t,t*=i; 105 f[i&1][i-1]=1; 106 for(int j=x+1;j<=y;++j) 107 f[i&1][j]=f[i&1^1][j-1]+f[i&1^1][j]*(i-1); 108 } 109 cout<<f[n&1][k]; 110 111 return 0; 112 }
[SLYZ] Arena | 一類斯特林數