首页 > 其他分享 >P1024 [NOIP2001 提高组] 一元三次方程求解( 普及- ) 题解

P1024 [NOIP2001 提高组] 一元三次方程求解( 普及- ) 题解

时间:2023-12-08 22:45:39浏览次数:36  
标签:lf% NOIP2001 int 题解 sqrt P1024 si double x1

题目传送门

思路:

1

可以直接暴力

2

二分搜索答案

3

盛金公式
一元三次方程:\(ax^3+cx^2+d=0\)
重根判别公式:
\(A=b^2-3ac\)
\(B=bc-9ad\)
\(C=c^2-3bd\)
当\(A=B=0\)时,\(X1=X2=X3= -b/3a= -c/b = -3d/c\)

4

牛顿迭代法:
对于一个已知的x值,每一次根据函数在这一点的导数,把x移动到,切线与x轴相交的地方。
即\(n+1]=x[n]-f(x)/f'(x)\)可以证明结果会趋近于函数的一个解。

5

勘根定理:
设函数f在闭区间\([a, b]\)中连续,且函数值\(f(a)\)与\(f(b)\)异号(即,一为正一为负)。则在区间\((a, b)\)中找到一个数c,使得\(f(c) = 0\)(即,\(c\)为函数\(f\)的根)。

Code:

暴力

#include <bits/stdc++.h>
using namespace std;
int main()
{
	double a,b,c,d;
	cin>>a>>b>>c>>d;
	for(double i=-100;i<=100;i+=0.001)//因为根的范围在-100~100之间,直接枚举-100~100的所有解
	{
		double j=i+0.001;
		double y1=a*i*i*i+b*i*i+c*i+d;
		double y2=a*j*j*j+b*j*j+c*j+d;
		if(y1>=0 and y2<=0||y1<=0 and y2>=0)
		{
			double x=(i+j)/2;
			printf("%.2lf ",x);
		}
	}
}

二分搜索

#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
double fc(double x)
{
	return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
	double l,r,m,x1,x2;
	int s=0,i;
	cin>>a>>b>>c>>d;
	for (i=-100;i<100;i++)
	{
		l=i; 
		r=i+1;
		x1=fc(l); 
		x2=fc(r);
		if(!x1)//判断左端点,是零点直接输出。
		{
			printf("%.2lf ",l); 
			s++;
		}
		//不能判断右端点,会重复。
		if(x1*x2<0)//区间内有根。
		{
			while(r-l>=0.001)//二分控制精度。
			{
				m=(l+r)/2;  //middle
				if(fc(m)*fc(r)<=0) 
					l=m; 
				else 
					r=m;//计算中点处函数值缩小区间。
			}
			printf("%.2lf ",r);//输出右端点。
			s++;
		}
		if (s==3) 
			break;//找到三个就退出大概会省一点时间
	}
	return 0;
}

盛金公式

#include <bits/stdc++.h>
using namespace std;
int main()
{
	double a,b,c,d;
	double as,bs,t,si;
	double x1,x2,x3;
	cin>>a>>b>>c>>d;
	as=b*b-3*a*c;
	bs=b*c-9*a*d;
	t=(2*as*b-3*a*bs)/(2*sqrt(as*as*as));
	si=acos(t);
	x1=(-b-2*sqrt(as)*cos(si/3))/(3*a);
	x2=(-b+sqrt(as)*(cos(si/3)+sqrt(3)*sin(si/3)))/(3*a);
	x3=(-b+sqrt(as)*(cos(si/3)-sqrt(3)*sin(si/3)))/(3*a);
	cout<<fixed<<setprecision(2)<<x1<<" ";
	cout<<fixed<<setprecision(2)<<x3<<" ";
	cout<<fixed<<setprecision(2)<<x2<<" ";
	return 0;
}

牛顿迭代法

#include <bits/stdc++.h>//不要问为什么我这个蒟蒻写的出来,问就是抄的
using namespace std;
struct func3 {
	double a, b, c, d;
	func3(double A = 0, double B = 0, double C = 0, double D = 0) {
		a = A;
		b = B;
		c = C;
		d = D;
	}
	double operator()(double x) {
		return ((a * x + b) * x + c) * x + d;
	}
	double dvt(double x) {
		return (3.0 * a * x + 2.0 * b) * x + c;
	}
};
void func3solve(func3 f, double st, double& val, double& sol) {
	for (int i = 1; !(abs(f(st)) < 1e-6) && i <= 100; i++) {
		st = st - f(st) / f.dvt(st);
	}
	val = f(st);
	sol = st;
}
double fix2(double sol) {
	return (double)int(sol * 100.0 + (sol > 0 ? 0.5 : -0.5)) / 100.0;
}
set<double>solutions;
int main() {
	double a, b, c, d;
	scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
	func3 f(a, b, c, d);
	for (double i = -100.0; i <= 100.0; i += 0.5) {
		double val, sol;
		func3solve(f, i, val, sol);
		sol = fix2(sol);
		if (abs(val) < 1e-6 && solutions.find(sol) == solutions.end())
			solutions.insert(sol);
	}
	for (set<double>::iterator it = solutions.begin(); it != solutions.end(); it++) {
		double x = (*it);
		printf("%.2lf ", x);
	}
	return 0;
}

勘根定理

#include <bits/stdc++.h>
using namespace std;
double a,b,c,d;
double f(double x)
{
	return (x*x*x*a+x*x*b+x*c+d);//计算一元三次方程的值
}
int main()
{
	double x1,x2,xx;
	scanf("%lf%lf%lf%lf",&a,&b,&c,&d);//都是实数,不一定非是整数 
	for(double i=-100;i<=100;i++) {//分别枚举
		x1=i;x2=i+1;
		if(f(x1)==0)//说明为零,直接输出
			printf("%.2lf ",i);
		if(f(x1)*f(x2)<0) {//小于零说明有零点,即说明有解。
			while(x2-x1>=0.001) {//范围 
				xx=(x1+x2)/2;//二分
				if(f(x1)*f(xx)<=0)//判断零点在x1到xx还是xx到x2
					x2=xx;//更新 
				else
					x1=xx;
			}
			printf("%.2lf ",x1);//输出 
		}
	}
}

标签:lf%,NOIP2001,int,题解,sqrt,P1024,si,double,x1
From: https://www.cnblogs.com/BadBadBad/p/P1024.html

相关文章

  • T404546 亮亮的玫瑰问题 2 题解
    再次被初中的自己搏杀,想到网络流去了LinkT404546亮亮的玫瑰问题2Question有\(n\)种花,第\(i\)种花有\(a_i\)个,求需要摆\(m\)朵花的方案数Solution定义\(F[i][j]\)表示前\(i\)种花,已经摆了\(j\)个的方案数枚举第\(i\)种花需要摆多少个\(k\)所以\(F[i][j......
  • [ARC164E] Segment-Tree Optimization 题解
    题目链接题目链接题目解法一个自认为比较自然的解法这种一段序列切成两部分的问题首先考虑区间\(dp\)令\(f_{l,r}\)为\([l,r]\)能构成的最小深度,\(g_{l,r}\)为在\(f_{l,r}\)最小的情况下最少的最大深度的点的个数转移枚举\(k\)即可需要在下面是叶子的时候处理一......
  • 2023.12.7 挑战杯题解
    选择题T1有序实数对即为数,坐标系中的点\(P\)即为形。故选择A。T2\(9.46\times10^{12}=9460000000000\)为\(13\)位数所以选D。T3如图所示,过点\(D\)作\(DE\botAB\),设\(AE=x\),在\(Rt\DeltaADE\)中利用勾股定理列方程为\((x-1)^2+10^2=x^2\),解得\(x=\frac{101}{2......
  • PTA-2023第十二次练习题目题解
    PTA-2023第十二次练习题目题解(祝大家机考顺利)以下代码已做防抄袭处理,切勿抄袭。注意:手机端因为屏幕限制,代码会有(不希望的)换行。解决方案:1.建议使用电脑端打开。2.点击代码进入全屏观看。6-24实验8_3_设计函数利用冒泡排序的思想,将每一列的最小值放到每列的最后一个位置。voi......
  • [AGC049D] Convex Sequence 题解
    题目链接点击打开链接题目解法好题!!考虑原题的限制相当于原序列下凸,即差分数组单调考虑把原序列在第一个最小值处割成\(2\)半因为原序列是凸的,所以非最小值的长度是\(\sqrt{2m}\)级别的这可以让我们\(dp\)差分数组,即求满足\(\sum\limits_{i=1}^{n'}ib_i=m'\)的\(b......
  • [ARC165E] Random Isolation 题解
    题目链接点击打开链接题目解法略有些套路的概率题,不过中间的把操作序列看成排列的操作还是很妙的首先套路的考虑期望的线性性,有两个方式:把贡献放在点上或点集上,这里采用后面的方式做对于每一个树上的集合\(S\),假设大小为\(n\),相邻的点为\(m\)考虑这个集合独立的限制为:相......
  • Emiya今天的饭 题解
    题目考虑条件主要食材最大的不超过总菜数的一半,不好处理,但存在主要食材最大的超过总菜数的一半是好处理的,容斥即可。首先计算所有情况,由于题目要求每个烹饪方式最多使用一次,很明显可以记\(g_i\)表示前\(i\)种烹饪方式的方案数。\[g_i=g_{i-1}+g_{i-1}\times\sum_{j=1}^......
  • 虚拟机运行Hadoop | 各种问题解决的心路历程
    ps:完成大数据技术实验报告的过程,出项各种稀奇古怪的问题。(知道这叫什么吗?经济基础决定上层建筑,我当时配置可能留下了一堆隐患,总之如果有同样的问题,希望可以帮到你)一、虚拟机网络连接不通的各种情况我这里遇到的是,三台虚拟机,两台piing百度不同原因:改了下内存,重启就又未知的网......
  • 【luogu题解】U388218 数数
    数数题目描述给定n个不超过1.5×10⁹的自然数。求这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。输入格式输入的第1行是整数n,表示自然数的个数。第2行到第n+1行每行一个自然数。输出格式输出文件包含m行(m为n个自然数中不相同数的个......
  • [ARC121F] Logical Operations on Tree 题解
    题目链接点击打开链接题目解法比较好的题首先要发现一个性质是:先删AND边,再删OR边最优小证一下:分类讨论AND边两端的数字情况\(0\&0\)左右两端虽然可能可以把\(1\)OR过来,但这种情况先做\(\&\),也一定可以OR得到\(1\)\(0\&1\)左边可能可以\(OR\)得到\(1......