[计蒜之道复赛 2018] 贝壳找房函数最值

Description

贝壳找房的攻城狮最近在研究一次函数 (f(x) = ax + b)

现在有 (n) 个一次函数,(f_i(x) = a_ix+b_i, i = {1 ... n})

容易发现,一次函数嵌套一次函数,还是一次函数。

[displaystyle f_{i}(f_{j}(x)) = a_{i} ( a_{j}x + b_{j}) + b_{i} ]

给定 (x),并且对于所有的 (f_i(x)) 可以任意改变顺序嵌套函数,求 (f(f(f(…f(x))…))的最大值。

Input

一个整数 (T ( T le 20 )) 代表数据组数。

每组数据:

第一行两个整数 (n, x) 代表一共有 (n) 个函数 (( 1 le n le 10000, 0 le x le 9))

第二行 (n) 个整数代表 (a_{i}) ,(1 le a_{i} le 9)

第三行 (n) 个整数代表 (b_{i}), (1 le b_{i} le 9)

Output

为了使问题简化,对于每组数据只需要输出最大值的个位即可。(比如函数的值可能是 (19) 或者 $ 23$ ,但最终应该输出的是 (3) )。

Solution

这题按照 ((a-1)/b) 的大小排序就好。

以下证明:

先解决 (x) 的问题。

假设当前有三个函数,参数分别为 (a_i,a_j,a_p)(b_i,b_j,b_p)

假设嵌套顺序是 (f_i(f_j(f_p(x))))

那么得到的函数将是

(ans=a_i(a_j(a_px+b_p)+b_j)+a_j\quad;;=a_i(a_ja_px+a_jb_p+b_j)+a_j\quad;;=a_ia_ja_px+a_ia_jb_p+a_ib_j+a_j)

观察到与 (x) 有关的一项跟函数的嵌套顺序无关,所以我们只需要让后面的 (a_i imes b_j imes ...) 最大即可。

继续假设。考虑一种简单点的情况,即当 (n=3) 时,三个方程编号分别是 (i,j,k)

我们通过调整法证明排序策略。

假设最外层嵌套的是第 (i) 个方程,那么我们需要决定的就是 (j,k) 谁在内层的问题。

先计算出两种情况的答案,分别是 (p) 在内层 (a_ia_jb_p+a_ib_j+b_i)(j) 在内层 (a_ia_pb_j+a_ib_p+b_i)

化简式子,分别是 (a_jb_p+b_j)(a_pb_j+b_p)

移项,((a_j-1)b_p)((a_p-1)b_j)

两边除过去,((a_j-1)/b_j)((a_p-1)/b_p)

假设 ((a_j-1)/b_j>(a_p-1)/b_p),那么最后的答案就是 (p) 在内层的答案要大于 (j) 在内层的答案。

所以按照 ((a-1)/b) 排序即可。

证毕。

Code

#include<cstdio>
#include<cctype>
#include<algorithm>

int T;
int n,m,tot;

struct Node{
	int a,b;
	friend bool operator<(Node x,Node y){
		return (x.a-1)*y.b>(y.a-1)*x.b;
	}
}node[10005];

int getint(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}

signed main(){
	T=getint();
	while(T--){
		tot=1;
		n=getint(),m=getint();
		for(int i=1;i<=n;i++){
			node[i].a=getint();
			tot=tot*node[i].a%10;
		}
		int ans=tot*m%10;
		for(int i=1;i<=n;i++)
			node[i].b=getint();
		std::sort(node+1,node+1+n);
		tot=1;
		for(int i=1;i<=n;i++){
			ans=(ans+tot*node[i].b%10)%10;
			tot=tot*node[i].a%10;
		}
		printf("%d
",ans%10);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/YoungNeal/p/9193714.html