luogu P1232 [NOI2013] 树的计数
不太懂题解里这个\(0.5\)是怎么出来的所以手写了个小数/youl
首先深度显然为bfs序上划分的段数,所以考虑对bfs序dp。
设\(f_i\)为划分到第\(i\)个的时候的所有方案深度之和,\(g_i\)为划分到第\(i\)个的时候的方案数。
考虑怎么样的划分是合法的。对于一段区间\([l,r]\),其前面已经划分好的点\([1,l-1]\)在dfs序序列上形成了若干个区间,而每个区间右端点的后面一个是必须要被包含在下一次划分的之内的。因此可以求出一个至少要划分到的位置。同时bfs序上的一段区间要求在dfs序上也升序,则可以处理出一个最多能划分到的位置。显然在这两个位置之间的是都可以转移的。因此直接差分即可。
但是有一个问题就是double存不下这么大的数因此要手动记录\(10^x\)。比较麻烦。
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=2e5+5,M=N*4+5,K=1e5+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;mt19937 rnd(time(0));
int n,m,k,x,y,z,A[N],B[N],p1[N],p2[N],R[N];
struct Node{
db x;int y;Node operator +(const Node &B)const{int d=max(y,B.y);if(y+20<d) return B;if(B.y+20<d)return (Node){x,y};return (Node){x/pow(10,d-y)+B.x/pow(10,d-B.y),d};}
Node operator -(const Node &B)const{return (Node){x,y}+(Node){-B.x,B.y};}
Node operator *(const Node &B)const{Node C;C.x=x*B.x;C.y=y+B.y;while(C.x>10) C.x/=10,C.y++;return C;}
db operator /(const Node &B)const{return x/B.x*pow(10,y-B.y);}
}f[N],g[N];
int main(){
freopen("1.in","r",stdin);
int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d",&A[i]),p1[A[i]]=i;for(i=1;i<=n;i++) scanf("%d",&B[i]),p2[B[i]]=i;
for(R[n]=n,i=n-1;i;i--) R[i]=(p1[B[i]]<p1[B[i+1]]?R[i+1]:i);f[1]=g[1]=(Node){1,0};f[2]=g[2]=(Node){-1,0};for(i=1;i<=n;i++){
f[i]=f[i]+f[i-1];g[i]=g[i]+g[i-1];while(f[i].x>10) f[i].x/=10,f[i].y++;while(g[i].x>10) g[i].x/=10,g[i].y++;x=max(x,max(p2[A[p1[B[i]]+1]],i+1));
if(x<=R[i+1]) f[x]=f[x]+f[i]+g[i],f[R[i+1]+1]=f[R[i+1]+1]-f[i]-g[i],g[x]=g[x]+g[i],g[R[i+1]+1]=g[R[i+1]+1]-g[i];if(i%100==0)cerr<<i<<' '<<g[i].x<<'\n';
}printf("%.3lf\n",f[n]/g[n]);
}