1. 程式人生 > 其它 >LuoguP5139 z小f的函式 題解

LuoguP5139 z小f的函式 題解

LuoguP5139 z小f的函式 題解

Content

給定 \(T\) 個二次函式 \(y=ax^2+bx+c\),有若干次操作,有一個操作編號 \(p\),保證僅為以下這五種:

  • 操作 \(1\):給定 \(k\),將函式影象向上移動 \(k\) 格(\(k<0\) 就是向下移動 \(-k\) 格)。
  • 操作 \(2\):給定 \(k\),將函式影象向右移動 \(k\) 格(\(k<0\) 就是向左移動 \(-k\) 格)。
  • 操作 \(3\):給定 \(k_1,k_2\),將函式影象關於點 \((k_1,k_2)\) 對稱。
  • 操作 \(4\):給定 \(k_1,k_2\),求函式影象在閉區間 \([k_1,k_2]\) 內的最大值和最小值並輸出(保留 \(2\)
    位小數)。
  • 操作 \(5\):給定 \(u,v,w\),求 \(y=ax^2+bx+c\) 的函式影象是否和 \(y=ux^2+vx+w\) 的函式影象有焦點,有的話輸出 2,否則輸出 0

在所有操作弄完以後,你還需要給出操作完以後函式的最值(顯然,根據 \(a\) 的正負來判定,保留 \(2\) 位小數)。

Range

  1. 關於 \(T,m\),有 \(T\leqslant 10,m\leqslant 10000\)
  2. 關於其他的變數,保證 \(a\neq0,u\neq0,a\neq u,1\leqslant p\leqslant5,-100\leqslant a,b,c,k_1,k_2,k,u,v,w\leqslant 100\)

Solution

我使用的是一般式進行操作。這麼做的優點是,你不需要花多餘的時間來求頂點式 \(a(x-h)^2+k\) 中的 \(h\)\(k\),前期處理比較方便,但問題是後面的計算量非常大,沒心理準備根本就是做到一半就崩潰了。所以,這篇題解旨在幫助大家多見識一些複雜的計算,讓你從容應對這麼多複雜的式子和分類討論。

話不多說,開始處理每個操作:

Part 1 操作 \(1\)

很顯然,我們將其上下移動以後改變的只是常數項的值。

什麼什麼,你還要我講原因?

那就請看圖吧:

上圖中藍色的曲線是函式 \(y=x^2+6x+5\) 的影象,而綠色的曲線是函式 \(y=x^2+6x+4\)

的影象。我們可以看到,藍色的曲線和 \(y\) 軸的交點是 \((5,0)\),而綠色的曲線和 \(y\) 軸的交點為 \((4,0)\),所以正好和常數項相對應。

或者我們也可以這樣:

\(y_1=a_1x^2+b_1x+c_1,y_2=a_2x^2+b_2x+c_2\)

令兩個函式的 \(x\) 都等於 \(0\),分別代入兩個函式中可得 \(y_1=c_1,y_2=c_2\)

本來這個很顯然的,但我想為了照顧那些還沒有學二次函式的學弟,所以還是寫寫吧。

故,操作後的函式為 \(y=ax^2+bx+c+k\)

Part 2 操作 \(2\)

這個用頂點式的話很方便,但是我們這裡只提一般式的做法,不過會借用一下頂點式。

首先,我們可以由頂點式 \(y=a(x-h)^2+s\)(由於為避免與題面中的 \(k\) 重複,故改為 \(s\))向右平移 \(k\) 格後的式子為 \(y=a(x-h-k)^2+s\),然後再把它拆開,得到:\(y=ax^2-(2ak+2ah)x+ah^2+ak^2+2ahk+s\)。又由於我們知道 \(h=-\dfrac{b}{2a},s=\dfrac{4ac-b^2}{4a}\),所以,直接將它強算過來,可以得到 \(y=ax^2+(b-2ak)x+ak^2-bk+c\)

故,操作後的函式為 \(y=ax^2+(b-2ak)x+ak^2-bk+c\)

Part 3 操作 \(3\)

首先,我們令一個在拋物線上的點為 \((x_0,y_0)\),所以我們就有在與 \((k_1,k_2)\) 對稱後的座標為 \((2k_1-x_0,2k_2-y_0)\)

什麼什麼,要我講原因?

可以,那請聽我說:由於它們的橫座標和縱座標之差分別為 \((x_0-k_1,y_0-k_2)\),所以它的對稱點的座標為 \((k_1-(x_0-k_1),k_2-(y_0-k_2))\Rightarrow(2k_1-x_0,2k_2-y_0)\)

那麼我們再代入到 \(y=ax^2+bx+c\) 中可得:\(2k_2-y_0=a(2k_1-x_0)^2+b(2k_1-x_0)+c\),因此可得到 \(y_0=2k_2-a(2k_1-x_0)^2-b(2k_1-x_0)-c\)

那麼再對右邊的式子進行化簡,然後再合併 \(x\) 同類項,可得到 \(y_0=-ax_0^2+(4ak_1+b)x_0+2k_2-4ak_1^2-2bk_1-c\)

故,操作後的函式為 \(y=-ax^2+(4ak_1+b)x+2k_2-4ak_1^2-2bk_1-c\)

Part 4 操作 \(4\)

這一段是我們的重頭戲。

首先根據 \(a<0\)\(a>0\) 兩大類,再通過 \(k_1,k_2\) 以及 \(x'=-\dfrac{b}{2a}\) 之間的關係進行分類討論。

筆者溫馨提示:自己畫一個函式影象具體分析,下面的兩個圖中作為例子的函式解析式左邊有。

好的,那麼現在就開始吧。

4.1 \(a<0\)

那麼這時候還需要 \(4\) 種情況來分類討論:

  1. \(k_2<x'\),此時可以從影象上看到,\(y_{\min}=ak_2^2+bk_2+c,y_{\max}=ak_1^2+bk_1+c\)

  2. \(k_2\geqslant x,k_1<x'\)\(k_2-x'<x'-k_1\),此時可以從影象上看到,\(y_{\min}=ax'^2+bx'+c,y_{\max}=ak_1^2+bk_1+c\)

  3. \(k_2\geqslant x,k_1<x'\)\(k_2-x'\geqslant x'-k_1\),此時可以從影象上看到 \(y_{\min}=ax'^2+bx'+c,y_{\max}=ak_2^2+bk_2+c\)

  4. \(k_1\geqslant x\),此時可以從影象上看到 \(y_{\min }=ak_1^2+bk_1+c,y_{\max}=ak_2^2+bk_2+c\)

4.2 \(a>0\)

同樣,這時候還需要 \(4\) 種情況來分類討論:

  1. \(k_2<x'\),此時可以從影象上看出 \(y_{\min}=ak_1^2+bk_1+c,y_{\max}=ak^2+bk_2+c\)

  2. \(k_2\geqslant x,k_1<x'\)\(k_2-x'<x'-k_1\),此時可以從影象上看到 \(y_{\min}=ak_1^2+bk_1+c,y_{\max}=ax'^2+bx'+c\)

  3. \(k_2\geqslant x,k_1<x\)\(k_2-x'\geqslant x'-k_1\),此時可以從影象上看到 \(y_{\min}=ak_2^2+bk_2+c,y_{\max}=ax'^2+bx'+c\)

  4. \(k_1\geqslant x\),此時可以從影象上看到 \(y_{\min}=ak_2^2+bk_2+c,y_{\max}=ak_1^2+bk_1+c\)

至此,所有的分類討論就完了,直接判斷條件對應輸出結果就好。

Part 5 操作 \(5\)

這個倒比操作 \(4\) 簡單,直接聯立一下就得到 \(ax^2+bx+c=ux^2+vx+w\)。所以,我們就只需要判斷這個方程是否有實數根就好了。

我們將上面這個方程移項,可以得到 \((a-u)x^2+(b-v)x+c-w=0\),所以,我們可以得到 \(\triangle=(b-v)^2-4(a-u)(c-w)\)。根據 \(\triangle\) 可以判別出這個方程實數根的情況,也就可以判斷這兩個函式影象是否有交點了。具體如下——

\(\triangle\geqslant 0\) 時,這個方程有實數根,這兩個函式影象也就有交點了;否則,當 \(\triangle<0\) 時,這個方程沒有實數根,這兩個函式影象也就沒有交點了。

至此,用一般式解決本題的演算法也就講完了。頂點式的話題解區裡的大佬們已經講得很清楚了。

如有不懂的話,下面的程式碼也許能幫助你。

Code

#include <cstdio>
#include <algorithm>
using namespace std;

int t;

double f(double a, double b, double c, double x) {
	return a * x * x + b * x + c;
}

int main() {
	scanf("%d", &t);
	while(t--) {
		double a, b, c;
		int m;
		scanf("%lf%lf%lf%d", &a, &b, &c, &m);
		while(m--) {
			int opt;
			scanf("%d", &opt);
			if(opt == 1) {
				double k;
				scanf("%lf", &k);
				double a0 = a, b0 = b, c0 = c + k;
				a = a0, b = b0, c = c0;
			} 
			else if(opt == 2) {
				double k;
				scanf("%lf", &k);
				double a0 = a, b0 = b - 2 * a * k, c0 = a * k * k - b * k + c;
				a = a0, b = b0, c = c0;
			}
			else if(opt == 3) {
				double k1, k2;
				scanf("%lf%lf", &k1, &k2);
				double a0 = -a, b0 = 4 * a * k1 + b, c0 = 2 * k2 - 4 * a * k1 * k1- 2 * b * k1 - c;
				a = a0, b = b0, c = c0;
			}
			else if(opt == 4) {
				double k1, k2, xp = -(b / (2 * a)), yp = (4 * a * c - b * b) / (4 * a);
				scanf("%lf%lf", &k1, &k2);
				if(a > 0) {
					if(k2 < xp)	{
						printf("%.2lf %.2lf\n", f(a, b, c, k2), f(a, b, c, k1));
					}
					else if(k1 < xp) {
						if(k2 - xp < xp - k1) {
							printf("%.2lf %.2lf\n", f(a, b, c, xp), f(a, b, c, k1));
						}
						else if(k2 - xp >= xp - k1) {
							printf("%.2lf %.2lf\n", f(a, b, c, xp), f(a, b, c, k2));
						}
					} else {
						printf("%.2lf %.2lf\n", f(a, b, c, k1), f(a, b, c, k2));
					}
				} else if(a < 0) {
					if(k2 < xp)	{
						printf("%.2lf %.2lf\n", f(a, b, c, k1), f(a, b, c, k2));
					}
					else if(k1 < xp) {
						if(k2 - xp < xp - k1) {
							printf("%.2lf %.2lf\n", f(a, b, c, k1), f(a, b, c, xp));
						}
						else if(k2 - xp >= xp - k1)	{
							printf("%.2lf %.2lf\n", f(a, b, c, k2), f(a, b, c, xp));
						}
					} else {
						printf("%.2lf %.2lf\n", f(a, b, c, k2), f(a, b, c, k1));
					}
				}
			}
			else if(opt == 5) {
				double u, v, w;
				scanf("%lf%lf%lf", &u, &v, &w);
				double delta = (b - v) * (b - v) - 4 * (a - u) * (c - w);
				puts(delta < 0 ? "0" : "2");
			}
		}
		printf("%.2lf\n", (4 * a * c - b * b) / (4 * a));
	}
	return 0;
}