zoukankan      html  css  js  c++  java
  • THUWC2017 在美妙的数学王国中畅游

    在美妙的数学王国中畅游

    数学王国中,每个人的智商可以用一个属于 ([0,1]) 的实数表示。数学王国中有 (n) 个城市,编号从 (0)(n-1) ,这些城市由若干座魔法桥连接。每个城市的中心都有一个魔法球,每个魔法球中藏有一道数学题。每个人在做完这道数学题之后都会得到一个在 ([0,1]) 区间内的分数。一道题可以用一个从 ([0,1]) 映射到 ([0,1]) 的函数 (f(x)) 表示。若一个人的智商为 (x) ,则他做完这道数学题之后会得到 (f(x)) 分。函数 (f) 有三种形式:

    • 正弦函数 (sin(a x + b) (a in [0,1], b in [0,pi],a+bin[0,pi]))

    • 指数函数 (e^{ax+b} (ain [-1,1], bin [-2,0], a+bin [-2,0]))

    • 一次函数 (ax + b (ain [-1,1],bin[0,1],a+bin [0,1]))

    数学王国中的魔法桥会发生变化,有时会有一座魔法桥消失,有时会有一座魔法桥出现。但在任意时刻,只存在至多一条连接任意两个城市的简单路径(即所有城市形成一个森林)。在初始情况下,数学王国中不存在任何的魔法桥。

    数学王国的国王拉格朗日很乐意传授小R数学知识,但前提是小R要先回答国王的问题。这些问题具有相同的形式,即一个智商为 (x) 的人从城市 (u) 旅行到城市 (v) (即经过 (u)(v) 这条路径上的所有城市,包括 (u)(v) )且做了所有城市内的数学题后,他所有得分的总和是多少。

    【小R教你学数学】

    若函数 (f(x))(n) 阶导数在 ([a,b]) 区间内连续,则对 (f(x))(x_0(x_0in[a,b])) 处使用 (n) 次拉格朗日中值定理可以得到带拉格朗日余项的泰勒展开式

    [f(x)=f(x_0)+frac{f'(x_0)(x-x_0)}{1!}+frac{f''(x_0)(x-x_0)^2}{2!}+ cdots +frac{f^{(n-1)}(x_0)(x-x_0)^{n-1}}{(n-1)!}+frac{f^{(n)}(xi)(x-x_0)^n}{n!},xin[a,b] ]

    其中,当 (x>x_0) 时,(xiin[x_0,x])。当 (x<x_0) 时,(xiin[x,x_0])

    (f^{(n)})表示函数 (f)(n) 阶导数

    【数据范围】

    对于 (100\%) 的数据,(1leq n leq 100000, 1leq m leq 200000)

    题解

    题面里面提示得很清楚了,直接泰勒展开就行了。开始我没看到……

    这题就是考你LCT板子和高中求导公式。

    [sin'(x)=cos(x)\ cos'(x)=-sin(x) ]

    展开式做到16项左右完全没问题。时间复杂度 (O(16 m log n))

    CO int N=100000+10;
    LL fac[16];
    int f[N];LD a[N],b[N];
    int ch[N][2],fa[N],rev[N];
    LD sum[N][16];
    
    IN bool nroot(int x){
    	return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
    }
    IN void push_up(int x){
    	for(int i=0;i<16;++i)
    		sum[x][i]=sum[ch[x][0]][i]+sum[ch[x][1]][i];
    	if(f[x]==1){ // sin
    		LD val=1,sine=sin(b[x]),cosine=cos(b[x]);
    		for(int i=0;i<16;i+=4){
    			sum[x][i]+=val*sine,val*=a[x];
    			sum[x][i+1]+=val*cosine,val*=a[x];
    			sum[x][i+2]-=val*sine,val*=a[x];
    			sum[x][i+3]-=val*cosine,val*=a[x];
    		}
    	}
    	else if(f[x]==2){ // exp
    		LD val=exp(b[x]);
    		for(int i=0;i<16;++i)
    			sum[x][i]+=val,val*=a[x];
    	}
    	else sum[x][0]+=b[x],sum[x][1]+=a[x];
    }
    IN void reverse(int x){
    	swap(ch[x][0],ch[x][1]),rev[x]^=1;
    }
    IN void push_down(int x){
    	if(rev[x]){
    		reverse(ch[x][0]),reverse(ch[x][1]);
    		rev[x]=0;
    	}
    }
    IN void rotate(int x){
    	int y=fa[x],z=fa[y],l=x==ch[y][1],r=l^1;
    	if(nroot(y)) ch[z][y==ch[z][1]]=x;fa[x]=z;
    	ch[y][l]=ch[x][r],fa[ch[x][r]]=y;
    	ch[x][r]=y,fa[y]=x;
    	push_up(y);
    }
    void splay(int x){
    	vector<int> stk(1,x);
    	for(int f=x;nroot(f);) stk.push_back(f=fa[f]);
    	for(;stk.size();stk.pop_back()) push_down(stk.back());
    	for(;nroot(x);rotate(x)){
    		int y=fa[x],z=fa[y];
    		if(nroot(y)) rotate((x==ch[y][1])!=(y==ch[z][1])?x:y);
    	}
    	push_up(x);
    }
    void access(int x){
    	for(int y=0;x;y=x,x=fa[x])
    		splay(x),ch[x][1]=y,push_up(x);
    }
    void make_root(int x){
    	access(x),splay(x),reverse(x);
    }
    int find_root(int x){
    	access(x),splay(x);
    	while(ch[x][0]) x=ch[x][0];
    	return x;
    }
    
    int main(){
    //	freopen("LOJ2289.in","r",stdin),freopen("LOJ2289.out","w",stdout);
    	fac[0]=1;
    	for(int i=1;i<16;++i) fac[i]=fac[i-1]*i;
    	int n=read<int>(),m=read<int>();
    	char type[3];scanf("%s",type);
    	for(int i=1;i<=n;++i){
    		read(f[i]),scanf("%Lf%Lf",a+i,b+i);
    		push_up(i);
    	}
    	while(m--){
    		char opt[10];scanf("%s",opt);
    		if(opt[0]=='a'){
    			int u=read<int>()+1,v=read<int>()+1;
    			make_root(u),fa[u]=v;
    		}
    		else if(opt[0]=='d'){
    			int u=read<int>()+1,v=read<int>()+1;
    			make_root(u),access(u);
    			splay(v),fa[v]=0; // edit 1:splay
    		}
    		else if(opt[0]=='m'){
    			int u=read<int>()+1;
    			read(f[u]),scanf("%Lf%Lf",a+u,b+u);
    			splay(u);
    		}
    		else{
    			int u=read<int>()+1,v=read<int>()+1;
    			LD x;scanf("%Lf",&x);
    			make_root(u);
    			if(find_root(v)!=u){
    				puts("unreachable");
    				continue;
    			}
    			LD val=1,ans=0;
    			for(int i=0;i<16;++i)
    				ans+=sum[v][i]*val/fac[i],val*=x;
    			printf("%.10Le
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    常用方法 反射常见方法
    常用方法 字符串是否是中文
    常用方法 读取 Excel的单位格 为 日期格式 的数据
    常用方法 保证数据长度相同
    常用方法 简单缓存
    P1821 [USACO07FEB]银牛派对Silver Cow Party
    P3905 道路重建
    关于宏定义
    P3512 [POI2010]PIL-Pilots
    P2398 GCD SUM
  • 原文地址:https://www.cnblogs.com/autoint/p/12069874.html
Copyright © 2011-2022 走看看