题解 P1232 【[NOI2013]树的计数】
分析
强烈吐槽一下这道题不采用取模的方式,害我被卡精度卡了半天。
因为毕竟是是自己yy的一种垃圾做法
手玩几组数据 (或者左转看看题解) 发现按层划分BFS序很科学。
然后就可以发现一个结论:一种合法的BFS序的划分对应一棵树。
证明:考虑递归构造对应关系。对于某个BFS序,如果我们已经构造出了
那么现在问题转化成合法地划分
在构造的时候实际上已经初步得出了一个层划分合法性的判定方法。
首先将BfS序中
根据题目的要求,第一个条件就是BfS序中
而构造的时候发现,删去的区间左端点一定是子树根,所以必须出现在划分中。
如果暴力枚举
首先,往
先枚举一个
然后从
对于
这样的话方程可以写成
事实上,我们要求的东西是
求个导看看:
将
设
其实这个东西可以直接用期望去推,但是人菜就只好用笨方法推方程咯!
所以成功地把
还可以优化吗?
之前发现的一个性质是,对于一个
那么显然
而
对于某个
而
这样的话两把指针扫一扫也是线性的了。这道题就这么被胡乱优化一波搞定了!
结果被卡精度了?!!!
开__float128也不行?!!!!
我搞了一波骚操作,把某个数科学计数法表示,然后重载加减法,忽略数量级超过一百的运算,然后就过了。。。。
代码
#include<bits/stdc++.h>
const int N = 2e5 + 10;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
struct Data {
double x; int e;
}g[N], f[N];
Data operator + (Data a, Data b) {
if(a.e < b.e)
std::swap(a, b);
int d = a.e - b.e; double l = b.x;
if(d > 100) l = 0;
else {
for(;d--;)
l /= 10;
}
a.x += l;
if(fabs(a.x) > 10) a.x /= 10, ++a.e;
return a;
}
void operator += (Data &a, Data b) {a = a + b;}
void operator -= (Data &a, Data b) {
b.x = -b.x;
a = a + b;
}
int a[N], b[N], psa[N], psb[N], n, must;
int main() {
n = ri();
for(int i = 1;i <= n; ++i)
a[i] = ri(), psa[a[i]] = i;
for(int i = 1;i <= n; ++i)
b[i] = ri(), psb[b[i]] = i;
int l = 0, r = 0;
f[1].x = g[1].x = 1;
f[2].x = g[2].x = -1;
for(int j = 1, i;j <= n; ++j) {
f[j] += f[j - 1]; g[j] += g[j - 1];
if(j == n) break;
l = std::max(l, psb[a[psa[b[j]] + 1]]);
for(r = std::max(r, j + 2);r <= n; ++r)
if(psa[b[r]] < psa[b[r - 1]])
break;
--r;
if(l <= r) {
f[l] += f[j]; f[r + 1] -= f[j];
g[l] += f[j] + g[j]; g[r + 1] -= f[j] + g[j];
}
}
int d = g[n].e - f[n].e; double x = g[n].x / f[n].x;
for(;d--;)
x *= 10;
printf("%.3lf\n", x);
return 0;
}