1. 程式人生 > >[SLYZ] Arena | 一類斯特林數

[SLYZ] Arena | 一類斯特林數

tar bigint LG long long 輸出 說明 length namespace bst

這個題據說是 OIBH 上面的,但網站大概已經不在了,網上也找不到這道題了,但這是一道好題,我就來寫一份題解吧。

問題描述(1s 65536KB)

近日,CWTV 網絡電視公司為了提高收視率,舉辦了一場 CWTV 拳擊擂臺賽。

一共有 n 名選手參賽,分別為A1A2……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 | 一類斯特林數