2019.01.24【THUWC2017】【BZOJ5020】【洛谷P4546】在美妙的数学王国中畅游(LCT)(泰勒展开)

BZOJ传送门

洛谷传送门


解析:

题目下方有一个提示。就是泰勒展开。

不过这道题的泰勒展开还算简单。

思路:

泰勒展开能够让我们将误差控制在一定范围的同时,快速维护多个函数的和。

主要思想是将非多项式函数拆成多项式维护每一项的系数。

如果对导数不是很了解的话可以看一下这篇博客:https://blog.csdn.net/qq_35649707/article/details/74611460

当然如果您现在不是很想了解的话,就记几个结论吧:

( a x ) ′ = a x ∗ ln ⁡ a (a^x)'=a^x*\ln a (ax)=axlna

特别的,我们有: ( e x ) ′ = e x (e^x)'=e^x (ex)=ex

三角函数的求导: cos ⁡ ( x ) ′ = − sin ⁡ ( x ) \cos(x)'=-\sin(x) cos(x)=sin(x) sin ⁡ ( x ) ′ = cos ⁡ ( x ) \sin(x)'=\cos(x) sin(x)=cos(x)

显然变化周期为 4 4 4

然后就是复合函数的求导: [ f ( g ( x ) ) ] ′ = g ′ ( x ) ∗ f ′ ( g ( x ) ) [f\big(g(x)\big)]'=g'(x)*f'(g(x)) [f(g(x))]=g(x)f(g(x))

放到这道题上,展开前面 sin ⁡ \sin sin函数,我们就能得到:
sin ⁡ ′ ( a x + b ) = a cos ⁡ ( a x + b ) \sin'(ax+b)=a\cos(ax+b) sin(ax+b)=acos(ax+b) sin ⁡ ′ ′ ( a x + b ) = − a 2 sin ⁡ ( a x + b ) \sin''(ax+b)=-a^2\sin(ax+b) sin(ax+b)=a2sin(ax+b) sin ⁡ ′ ′ ′ ( a x + b ) = − a 3 cos ⁡ ( a x + b ) \sin'''(ax+b)=-a^3\cos(ax+b) sin(ax+b)=a3cos(ax+b)

维护11项精度就足够了(因为泰勒展开里面除了一个阶乘)

对于 e x e^x ex
( e a x + b ) ( n ) = a n e a x + b (e^{ax+b})^{(n)}=a^ne^{ax+b} (eax+b)(n)=aneax+b

展开后LCT维护就是了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<18|1;
		char buf[Rlen],*p1,*p2;
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re char c;
		while(!isdigit(c=gc()));re int num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline double getdb(){
		re char c;
		re bool f=0;
		while(!isdigit(c=gc()))if(c=='-')f=1;re double x=c^48;
		while(isdigit(c=gc()))x=x*10+(c^48);
		if(c!='.')return f?-x:x;
		re double y=1.0;
		while(isdigit(c=gc()))x+=(y/=10)*(c^48);
		return f?-x:x;
	}
	inline char getop(){
		re char c;
		while(isspace(c=gc()));return c;
	}
}
using namespace IO;

cs int N=100005,M=11;

int n,m;

int fa[N],son[N][2];
bool rev[N];
double coef[N][M+1],sum[N][M+1];
ll fac[M];

inline bool which(int now){return son[fa[now]][1]==now;}
inline bool isroot(int now){return !fa[now]||(son[fa[now]][0]!=now&&son[fa[now]][1]!=now);}

inline void pushup(int now){
	for(int re i=0;i<=M;++i)
	sum[now][i]=coef[now][i]+sum[son[now][0]][i]+sum[son[now][1]][i];
}

inline void pushdown(int now){
	if(rev[now]){
		rev[now]=0;
		swap(son[now][0],son[now][1]);
		if(son[now][0])rev[son[now][0]]^=1;
		if(son[now][1])rev[son[now][1]]^=1;
	}
}

inline void Rotate(int now){
	re int Fa=fa[now],FA=fa[Fa];
	re bool pos=which(now);
	if(FA&&!isroot(Fa))son[FA][which(Fa)]=now;
	son[Fa][pos]=son[now][!pos];
	if(son[Fa][pos])fa[son[Fa][pos]]=Fa;
	son[now][!pos]=Fa;
	fa[Fa]=now;
	fa[now]=FA;
	pushup(Fa);
	pushup(now);
}

inline void Splay(int now){
	static int q[N],qn;
	q[qn=1]=now;
	for(int re Fa=now;!isroot(Fa);Fa=fa[Fa])q[++qn]=fa[Fa];
	while(qn)pushdown(q[qn--]);
	for(int re Fa;!isroot(now);Rotate(now))
	if(!isroot(Fa=fa[now]))Rotate(which(Fa)==which(now)?Fa:now);
}

inline void access(int now){
	for(int re ch=0;now;ch=now,now=fa[now])
	Splay(now),son[now][1]=ch,pushup(now);
}

inline void makeroot(int now){
	access(now);
	Splay(now);
	rev[now]^=1;
}

inline int findroot(int now){
	access(now);
	Splay(now);
	while(son[now][0])now=son[now][0];
	Splay(now);
	return now;
}

inline void link(int u,int v){
	makeroot(u);fa[u]=v;
}

inline void cut(int u,int v){
	makeroot(u);
	access(v);
	Splay(v);
	fa[u]=son[v][0]=0;
	pushup(v);
}

inline void Set(int now,int typ,double a,double b){
	memset(coef[now],0,sizeof coef[now]);
	switch(typ){
		case 1:{
			re double o=1,Sin=sin(b),Cos=cos(b);
			for(int re i=0;i<=M;++i)coef[now][i]=((i&1)?Cos:Sin)*((i%4<=1)?1:-1)*o/fac[i],o*=a;
			break;
		}
		case 2:{
			re double o=1,Exp=exp(b);
			for(int re i=0;i<=M;++i)coef[now][i]=Exp*o/fac[i],o*=a;
			break;
		}
		case 3:{
			coef[now][1]=a,coef[now][0]=b;
			break;
		}
	}
}

inline void change(int u,int f,double a,double b){
	Splay(u);
	Set(u,f,a,b);
	pushup(u);
}

inline void query(int u,int v,double x){
	makeroot(u);
	if(findroot(v)!=u){
		puts("unreachable");
		return;
	}
	Splay(v);
	double res=0;
	for(int re i=M;~i;--i){
		res*=x;
		res+=sum[v][i];
	}
	printf("%.7f\n",res);
} 

signed main(){
	fac[0]=1;
	for(int re i=1;i<=M;++i)fac[i]=fac[i-1]*i;
	n=getint(),m=getint();getint();
	for(int re i=1;i<=n;++i){
		int f=getint();
		double a=getdb(),b=getdb();
		Set(i,f,a,b);
	}
	while(m--){
		char op=getop();
		int u=getint(),v=getint();
		double a,b;
		switch(op){
			case 'a':link(u+1,v+1);break;
			case 'd':cut(u+1,v+1);break;
			case 'm':a=getdb(),b=getdb();change(u+1,v,a,b);break;
			case 't':a=getdb();query(u+1,v+1,a);break;
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值