【THUWC2017】在美妙的数学王国中畅游(bzoj5020)
我数学是真的菜!!
清华光用数学知识就把我吊起来打,我还是太菜了
题解
如果每座城市的 $f$ 都是 $3$,维护一下树的路径上的 $\sum a,\space \sum b$ 即可。
其实就是维护一次项和常数项。由于只有两项,所以很好维护。
这样维护的原理是多项式(这里是一次函数)可以合并,所以要求一条路径的答案,只要把 $x$ 代入这条路径上所有点合并后的多项式即可。
由于前三个操作需要动态树,套 $LCT$ 即可(我强行再学一遍 $LCT$……)
但 $sin(ax+b)$ 和 $e(ax+b)$ 都不是多项式,没法合并啊!(也就是说我们只能暴力求路径上每个点的答案再求和)
然后思考一下,看看题,发现底部给了你一个泰勒展开的公式。
泰勒展开是什么?就是通过求导数,把一个奇怪的函数展开成多项式。这个多项式的项数无穷多,但我们可以只保留前面若干项,保留的项数越多,这个多项式的结果就越接近原函数的结果。(因为越往后的项,值越接近无穷小,小到 $10^{-???}$ 次方的那种,可以忽略不计)
再看一下输出要求,答案只要精确到 $10^{-7}$ 就行,然后应该就明白要干什么了……
泰勒公式:$$f(x)=\sum_{i=0}^{n} \frac{f^{(i)}(x_0)*(x-x_0)^i}{i!}$$
其中 $f^{(i)}(x)$ 表示函数 $f(x)$ 的 $i$ 阶导。
这个公式的 $x_0$ 是随便取都可以的,没有区别……只是让你随便代进去一个数而已。
但是 $x_0=0$ 的时候最方便,上式就变成了 $$f(x)=\sum_{i=0}^{n} \frac{f^{(i)}(0)*x^i}{i!}$$
而且这就使函数 $f^{(i)}$ 的自变量 $x=0$ ,也就是说不用管 $x$ 的系数 $a$ 了,在维护时只需要用到它的系数 $b$。下文会再提到。
然后复习一下怎么求导吧……(雾)
指数函数求导:$$(a^x)'=a^x*\ln a$$
($ln\space a$ 代表取自然对数,即底数为 $e$)
特殊的:$$(e^x)'=e^x$$
三角函数求导:$$(\sin x)'=\cos x$$
$$(\cos x)'=-\sin x$$
$$(-\sin x)'=-\cos x$$
$$(-\cos x)'=\sin x$$
四个一循环,其实就是圆上的四个象限。
复合函数的求导公式: $$[f(g(x))]'=g'(x)\times f'(g(x))$$
这道题中,函数 $f$ 就是第一问和第二问要求的那两个式子本身,函数 $g$ 则是 $g(x)=ax+b$。
对于第二问,$f(x)=e^{ax+b}$,则 $f(g(x))=e^{ax+b}$ 求一次导后得到 $$[f(g(x))]'=a\times e^{ax+b}$$
然后再对 $[f(g(x))]'$ 求导,当时我就有一个没搞明白的地方:为什么 $a$ 求导后不是 $0$?它不是常数项吗?
后来我才发现,$[f(g(x))]'$ 中的 $a$ 不是常数项,是与变量 $x$ 有关的系数!注意它乘的 $e^{ax+b}$ 里是有个 $x$ 的。
所以再对 $[f(g(x))]'$ 求导,也就是对 $f(g(x))$ 求二次导时不对若干次项的系数 $a$ 求导,直接乘上即可,重点是对 $e^{ax+b}$ 求导。所以 $$[f(g(x))]''=a^2\times e^{ax+b}$$
以此类推,$$[f(g(x))]^{(n)}=a^n\times e^{ax+b}$$
对于第一问的三角函数求导同理,$$\sin'(ax+b)=a \cos(ax+b)$$
$$\sin''(ax+b)=-a^2 \sin(ax+b)$$
$$\sin'''(ax+b)=-a^3 \cos(ax+b)$$
$$\sin''''(ax+b)=a^4 \sin(ax+b)$$
以此类推的循环。
由于我们之前让自变量 $x=x_0=0$ 了,所以实际维护以上所有信息时不用算和 $x$ 相关的项(而且输入的 $x$ 不唯一,本身就没法维护。这就是为什么让那个随意值 $x_0$ 为 $0$ 会很方便)。
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define rep(i,x,y) for(int i=x;i<=y;++i) 4 #define N 200002 5 #define M 16 6 using namespace std; 7 inline int read(){ 8 int x=0; bool f=1; char c=getchar(); 9 for(;!isdigit(c);c=getchar()) if(c=='-') f=0; 10 for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 11 if(f) return x; 12 return 0-x; 13 } 14 int n,m,k,f[N]; 15 char type[2]; 16 double jc[N],sum[N][M],a[N],b[N]; 17 int ch[N][2],fa[N]; 18 bool rev[N]; 19 20 ;inline bool son(int x){return ch[fa[x]][1]==x;} 21 inline bool isroot(int x){return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;} 22 inline void reverse(int x){ 23 if(!x) return; 24 swap(ch[x][0],ch[x][1]), rev[x]^=1; 25 } 26 void pushup(int x){ 27 rep(i,0,M-1) sum[x][i]=sum[ch[x][0]][i]+sum[ch[x][1]][i]; 28 if(f[x]==1){ 29 double val=1,Sin=sin(b[x]),Cos=cos(b[x]); 30 for(int i=0;i<M;i+=4){ 31 sum[x][i]+=Sin*val, val*=a[x]; 32 sum[x][i+1]+=Cos*val, val*=a[x]; 33 sum[x][i+2]-=Sin*val, val*=a[x]; 34 sum[x][i+3]-=Cos*val, val*=a[x]; 35 } 36 } 37 else if(f[x]==2){ 38 double val=exp(b[x]); sum[x][0]+=val; 39 for(int i=1;i<M;++i) 40 val*=a[x], sum[x][i]+=val; 41 } 42 else 43 sum[x][0]+=b[x], sum[x][1]+=a[x]; 44 } 45 void pushdown(int x){ 46 if(!rev[x]) return; 47 reverse(ch[x][0]), reverse(ch[x][1]), rev[x]=0; 48 } 49 void rotate(int x){ 50 int f=fa[x], g=fa[f], c=son(x); 51 ch[f][c]=ch[x][c^1]; 52 if(ch[f][c]) fa[ch[f][c]]=f; 53 fa[x]=g; 54 if(!isroot(f)) ch[g][son(f)]=x; 55 ch[x][c^1]=f, fa[f]=x, pushup(f); 56 } 57 int stk[N],top; 58 void splay(int x){ 59 stk[++top]=x; 60 for(int i=x;!isroot(i);i=fa[i]) stk[++top]=fa[i]; 61 while(top) pushdown(stk[top--]); 62 for(;!isroot(x);rotate(x)) 63 if(!isroot(fa[x])) son(x)^son(fa[x]) ? rotate(x) : rotate(fa[x]); 64 pushup(x); 65 } 66 void access(int x){ 67 for(int y=0; x; y=x,x=fa[x]) 68 splay(x), ch[x][1]=y, pushup(x); 69 70 } 71 void makeroot(int x){ 72 access(x), splay(x), reverse(x); 73 } 74 int findroot(int x){ 75 access(x), splay(x); 76 while(ch[x][0]) x=ch[x][0]; 77 splay(x); return x; 78 } 79 void split(int x,int y){ 80 makeroot(x), access(y), splay(y); 81 } 82 void link(int x,int y){ 83 makeroot(x), fa[x]=y; 84 } 85 void cut(int x,int y){ 86 split(x,y), ch[y][0]=fa[x]=0; 87 } 88 89 inline void getJc(){ 90 jc[0]=jc[1]=1; 91 rep(i,2,M-1) jc[i]=jc[i-1]*i; 92 } 93 int main(){ 94 getJc(); 95 n=read(),m=read(); 96 scanf("%s",type); 97 rep(i,1,n) scanf("%d %lf %lf",&f[i],&a[i],&b[i]); 98 while(m--){ 99 int u,v,ff; 100 double aa,bb,x,IQ,ans; 101 char s[10]; 102 scanf("%s",s); 103 if(s[0]=='a'){ 104 u=read()+1,v=read()+1; 105 link(u,v); 106 } 107 else if(s[0]=='d'){ 108 u=read()+1,v=read()+1; 109 cut(u,v); 110 } 111 else if(s[0]=='m'){ 112 scanf("%d %d %lf %lf",&u,&ff,&aa,&bb); 113 ++u; 114 makeroot(u); 115 f[u]=ff, a[u]=aa, b[u]=bb; 116 pushup(u); 117 } 118 else{ 119 scanf("%d %d %lf",&u,&v,&IQ); 120 x=1, ++u, ++v; 121 if(findroot(u)^findroot(v)){ 122 printf("unreachable\n"); 123 continue; 124 } 125 split(u,v); 126 ans=0; 127 rep(i,0,M-1) 128 ans+=sum[v][i]*x/jc[i], x*=IQ; 129 printf("%.8e\n",ans); 130 } 131 } 132 return 0; 133 }
如果你数学学得好,这题就是个 $LCT$ 裸题(前提是你能熟练秒切 $LCT$)
然而裸题效果对我明显无效