码迷,mamicode.com
首页 > 其他好文 > 详细

[SLYZ] Arena | 一类斯特林数

时间:2018-03-04 21:13:32      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:分析   start   ack   输入   har   baidu   clear   gpo   round   

这个题据说是 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 | 一类斯特林数

标签:分析   start   ack   输入   har   baidu   clear   gpo   round   

原文地址:https://www.cnblogs.com/milky-w/p/8505875.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!