国王游戏
有一个长度为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();
}