国王游戏

国王游戏

有一个长度为n的二元组数列\((a_i,b_i)\),定义一个位置i的权值为\([\frac{\prod_{i=1}^{i-1}a_i}{b_{i}}]\)(显然\(i>1\)),现在允许你将后n-1个位置的顺序自由交换,询问权值的最大值的最小值,\(n\leq 1000\)

显然问题带有浓厚的二分性,但是二分无法判断是否能更优秀,自然倍增也萎掉了,如果使用递推,后面的问题类似全排列,你要么是二进制压缩记录选没选,要么是按照一个顺序,将数字填入序列,显然两者皆萎了,考虑递推兄弟贪心。

考虑微扰法,考虑两个相邻位置\(i,i+1\)而言,显然这两个位置对答案的影响即(先不考虑向下取整,因为非向下取整得到的关系,考虑了向下取整后,最多是大于关系变成大于等于关系)

\[\max(\frac{a_1a_2...a_{i-1}}{b_i},\frac{a_1a_2...a_{i-1}a_i}{b_{i+1}}) \]

而交换了位置,对答案的影响即

\[\max(\frac{a_1a_2...a_{i-1}}{b_{i+1}},\frac{a_1a_2...a_{i-1}a_{i+1}}{b_{i}}) \]

显然,相同的项,不会影响大小比较,提出来,即比较

\[\max(\frac{1}{b_i},\frac{a_i}{b_{i+1}}) \]

\[\max(\frac{1}{b_{i+1}},\frac{a_{i+1}}{b_{i}}) \]

显然分式不好比较,同时乘一个\(b_ib_{i+1}\),于是就是比较

\[\max(b_{i+1},a_ib_i),\max(b_i,a_{i+1}b_{i+1}) \]

注意到\(a_ib_i\geq b_i,a_{i+1}b_{i+1}\geq b_{i+1}\),于是即比较

\[a_ib_i,a_{i+1}b_{i+1} \]

到此,我们就发现只要二元组两个元的乘积只要前者小于后者,就意味着不交换比交换优秀,反之,显然只要交换者排序,也就是冒泡排序,就可以得到最优解。

于是,根据冒泡排序的性质,容易知道,以\(a_ib_i\)为关键字进行冒泡排序,最终必然可以得到该个关键字的递增序列,也就是说,我们可以直接对这个关键字进行快速排序或者归并排序,\(O(n)\)统计答案,然后就可以做到时间复杂度\(O(nlogn)\)

但是这道题要高精,也许我算出来的时间复杂度并不对?

参考代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define il inline
#define ri register
#define lb long double
#define Size 1500
using namespace std;
struct lll{
    int num[4250];
    il void clear(){
        memset(num,0,sizeof(num));
    }
    il lll(){
        clear(),num[0]=1;
    }
    il void print(){
        for(ri int i(num[0]);i;--i)
            putchar(num[i]+48);putchar('\n');
    }
    template<class free>
    il void operator=(free x){num[0]^=num[0];
        do num[++num[0]]=x%10,x/=10;while(x);
    }template<class free>
    il void operator*=(free x){
        ri int i,j(0);
        for(i=1;i<=num[0]||j;++i)
            (num[i]*=x)+=j,j=num[i]/10,num[i]%=10;
        while(i>1&&!num[i])--i;num[0]=i;
    }
    il lll operator/(int x){
        lll y;ri int i,j(0);
        for(int i(num[0]);i;--i)
            j=j*10+num[i],
                y.num[i]=j/x,j%=x;
        i=num[0];while(i>1&&!y.num[i])--i;
        return y.num[0]=i,y;
    }
    il bool operator<(lll x){
        if(num[0]<x.num[0])return true;
        if(num[0]>x.num[0])return false;
        for(ri int i(num[0]);i;--i)
            if(num[i]<x.num[i])return true;
            else if(num[i]>x.num[i])return false;
        return false;
    }
}gzy,ans;
struct inter{
    int l,r,key;
    il bool operator<(const inter&x){
        return key<x.key;
    }
}I[Size];
il void read(int&);
int main(){
    int n;read(n),++n;
    for(int i(1);i<=n;++i)
        read(I[i].l),read(I[i].r),
            I[i].key=I[i].l*I[i].r;
    sort(I+2,I+n+1),gzy=I[1].l;
    for(int i(2);i<=n;gzy*=I[i].l,++i)
        if(ans<gzy/I[i].r)
            ans=gzy/I[i].r;
    ans.print();
    return 0;
}
il void read(int &x){
    x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
posted @ 2019-07-20 12:31  a1b3c7d9  阅读(436)  评论(0编辑  收藏  举报