清华冬令营的某题

    xiaoxiao2021-03-25  149

    问题背景

    数字和数学规律主宰着这个世界。 机器的运转, 生命的消长, 宇宙的进程, 这些神秘而又美妙的过程无不可以用数学的语言展现出来。 这印证了一句古老的名言: “学好数理化,走遍天下都不怕。”

    问题描述

    学渣小R被大学的数学课程虐得生活不能自理,微积分的成绩曾是他在教室里上的课的最低分。然而他的某位陈姓室友却能轻松地在数学考试中得到满分。为了提升自己的数学课成绩,有一天晚上(在他睡觉的时候),他来到了数学王国。

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

    正弦函数sin(ax b) (a[0,1],b[0,π],a b[0,π])

    指数函数 eax+b (a[1,1],b[2,0],a+b[2,0]) 一次函数 ax+b (a[1,1],b[0,1],a+b[0,1])

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

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

    输入格式

    第一行两个正整数 n,m和一个字符串 type 。表示数学王国中共有 n 座城市,发生了m个事件,该数据的类型为 type type 字符串是为了能让大家更方便地获得部分分,你可能不需要用到这个输入。其具体含义在限制与约定中有解释。

    接下来 n 行,第i行表示初始情况下编号为 i 的城市的魔法球中的函数。一个魔法用一个整数 f 表示函数的类型,两个实数 a,b 表示函数的参数,若

    f=1 ,则函数为 f(x)=sin(ax+b)(a[0,1],b[0,π],a+b[0,π]) f=2 ,则函数为 f(x)=eax+b(a[1,1],b[2,0],a+b[2,0]) f=3 ,则函数为 f(x)=ax+b(a[1,1],b[0,1],a+b[0,1])

    接下来 m 行,每行描述一个事件,事件分为四类。

    appear u v 表示数学王国中出现了一条连接u v 这两座城市的魔法桥(0u,v<n,uv) ,保证连接前 u v这两座城市不能互相到达。

    disappear u v 表示数学王国中连接 u v这两座城市的魔法桥消失了,保证这座魔法桥是存在的。magic c f a b 表示城市 c 的魔法球中的魔法变成了类型为f,参数为 a,b 的函数travel u v x 表示询问一个智商为 x 的人从城市u旅行到城市 v (即经过u v 这条路径上的所有城市,包括u v )后,他得分的总和是多少。若无法从u到达 v ,则输出一行一个字符串 unreachable。

    输出格式

    对于每个询问,输出一行实数,表示得分的总和。

    限制与约定

    对于100%的数据,1n100000,1m200000 。 本题共有20个数据点,每个数据点5分。 时限:5s

    数据类型的含义: A:不存在 disappear 事件,且所有appear事件中的 u=v1 B:不存在 disappear 事件 C:所有的 travel 事件经过的城市总数 5000000 (不可到达的城市对不计入在内) D:无限制 0:所有 travel 事件中, x=1 (即所有人的智商均为 1 ) 1:无限制

    评分标准

    如果你的答案与标准答案的相对误差在107以内或绝对误差在 107 以内,则被判定为正确。

    如果你的所有答案均为正确,则得满分,否则得0分。

    请注意输出格式:每行输出一个答案,答案只能为 unreachable 或者一个实数(建议使用科学计数法表示)。每行的长度不得超过50。错误输出格式会被判定为0分。

    小R教你学数学

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

    f(x)=f(x0) f(x0)(xx0)1! f(x0)(xx0)22! f(n1)(x0)(xx0)n1(n1)! f(n)(ξ)(xx0)nn!,x[a,b]

    其中,当 x>x0 时, ξ[x0,x] 。当 x<x0 时, ξ[x,x0]

    f(n) 表示函数 f n阶导数

    Solution

    LCT的题目,比较裸。关键是怎么维护函数的性质。 考虑题目后面告诉我们的数学知识,我们可以把函数转换成k次多项式系数表示的方式,这三个函数的k阶导数都比较好求,为了好算我们取公式中的 x0 为0,然后只需要保存下来每个节点函数的k次项系数。本人亲测k要取10以上才能保证精度。这样的话维护系数很方便。为了提高精度我们还可以把式子中的阶乘项在统计答案的时候再除(不过好像没必要)。 然后就是普通的LCT操作了……

    代码:

    #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; inline int read(){ int xx=0,f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())xx=xx*10+ch-'0'; return xx*f; } const int maxn=100010,max0=10; struct node{ int fa,ch[2]; double sum[max0+1],data[max0+1]; bool is_root,reverse; }T[maxn]; int n,m,num; char type[maxn]; int getson(int x){ return (x==T[T[x].fa].ch[1]); } void pushreverse(int x){ if(!x)return; swap(T[x].ch[0],T[x].ch[1]); T[x].reverse^=1; } void pushdown(int x){ if(T[x].reverse){ pushreverse(T[x].ch[0]); pushreverse(T[x].ch[1]); T[x].reverse=false; } } void update(int x){ memset(T[x].sum,0,sizeof T[x].sum); for(int i=0;i<=max0;i++)T[x].sum[i]+=T[x].data[i]; if(T[x].ch[0]){ for(int i=0;i<=max0;i++)T[x].sum[i]+=T[T[x].ch[0]].sum[i]; } if(T[x].ch[1]){ for(int i=0;i<=max0;i++)T[x].sum[i]+=T[T[x].ch[1]].sum[i]; } } void rotate(int x){ if(T[x].is_root)return; int k=getson(x),fa=T[x].fa,fafa=T[fa].fa; pushdown(fa);pushdown(x); T[fa].ch[k]=T[x].ch[k^1]; if(T[x].ch[k^1])T[T[x].ch[k^1]].fa=fa; T[x].ch[k^1]=fa;T[fa].fa=x; T[x].fa=fafa; if(!T[fa].is_root)T[fafa].ch[fa==T[fafa].ch[1]]=x; else T[x].is_root=true,T[fa].is_root=false; update(fa);update(x); } void push(int x){ if(!T[x].is_root)push(T[x].fa); pushdown(x); } void Splay(int x){ push(x); for(int fa;!T[x].is_root;rotate(x)){ if(!T[fa=T[x].fa].is_root){ rotate((getson(x)==getson(fa))?fa:x); } } } void access(int x){ int y=0; do{ Splay(x);pushdown(x); T[T[x].ch[1]].is_root=true; T[T[x].ch[1]=y].is_root=false; update(x);x=T[y=x].fa; }while(x); } void mroot(int x){ access(x);Splay(x);pushreverse(x); } void link(int u,int v){ mroot(u);T[u].fa=v; } void cut(int u,int v){ mroot(u); Splay(v); T[T[v].ch[0]].fa=T[v].fa; T[T[v].ch[0]].is_root=true; update(T[v].ch[0]); T[v].fa=0;T[v].ch[0]=0; } bool judge(int u,int v){ while(T[u].fa)u=T[u].fa; while(T[v].fa)v=T[v].fa; return u==v; } void get_sin(int x,double a,double b){ T[x].data[0]=sin(b); double f=1,temp=a; for(int i=1;i<=max0;i++,temp*=a){ if(!(i&1)){ f*=-1; T[x].data[i]=f*temp*sin(b); } else T[x].data[i]=f*temp*cos(b); } } void get_pow(int x,double a,double b){ double temp=1; for(int i=0;i<=max0;i++,temp*=a){ T[x].data[i]=temp*exp(b); } } void get_funtion(int x,double a,double b){ T[x].data[0]=b;T[x].data[1]=a; for(int i=2;i<=max0;i++)T[x].data[i]=0; } int main(){ freopen("math.in","r",stdin); freopen("math.out","w",stdout); n=read();m=read();scanf("%*s"); for(int i=1;i<=n;i++)T[i].is_root=true; for(int i=1,opt;i<=n;i++){ double a,b; opt=read();scanf("%lf%lf",&a,&b); if(opt==1)get_sin(i,a,b); else if(opt==2)get_pow(i,a,b); else get_funtion(i,a,b); update(i); } while(m--){ int u,v,f; double a,b,x; scanf("%s",type); if(type[0]=='a'){ u=read();v=read(); link(++u,++v); } else if(type[0]=='d'){ u=read();v=read(); cut(++u,++v); } else if(type[0]=='m'){ u=read();f=read();scanf("%lf%lf",&a,&b); Splay(++u); if(f==1)get_sin(u,a,b); else if(f==2)get_pow(u,a,b); else get_funtion(u,a,b); update(u); } else{ u=read();v=read();scanf("%lf",&x); if(judge(++u,++v)){ mroot(u);access(v);Splay(u); double ans=0,temp=1,jie=1; for(int i=0;i<=max0;jie*=(++i),temp*=x){ ans+=T[u].sum[i]*temp/jie; } printf("%.10lf\n",ans); } else puts("unreachable"); } } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-11715.html

    最新回复(0)