码迷,mamicode.com
首页 > 其他好文 > 详细

THUWC2017 在美妙的数学王国中畅游

时间:2019-12-19 21:23:55      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:edit   ++i   情况   直接   智商   tor   问题   roo   左右   

在美妙的数学王国中畅游

数学王国中,每个人的智商可以用一个属于 \([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+b\in[0,\pi])\)

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

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

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

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

【小R教你学数学】

若函数 \(f(x)\)\(n\) 阶导数在 \([a,b]\) 区间内连续,则对 \(f(x)\)\(x_0(x_0\in[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!},x\in[a,b] \]

其中,当 \(x>x_0\) 时,\(\xi\in[x_0,x]\)。当 \(x<x_0\) 时,\(\xi\in[x,x_0]\)

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

【数据范围】

对于 \(100\%\) 的数据,\(1\leq n \leq 100000, 1\leq 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\n",ans);
        }
    }
    return 0;
}

THUWC2017 在美妙的数学王国中畅游

标签:edit   ++i   情况   直接   智商   tor   问题   roo   左右   

原文地址:https://www.cnblogs.com/autoint/p/12069874.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!