大石头路73号 2018-05-16
BZOJ3244
不会做orz
我们要挖掘出\(bfs\)序和\(dfs\)序的性质
①容易知道\(bfs\)序一定是一层一层的,如果我们能确定在\(bfs\)序中各层的断点,就能确定深度
②由于\(bfs\)序和\(dfs\)序儿子遍历顺序是一样的,所以\(bfs\)序同一层的点,在\(dfs\)序中顺序也一样,如果存在\(u,v\)在\(bfs\)中相邻,而在\(dfs\)序中逆序,那么\(u,v\)之间一定有断点
③\(dfs\)序中相邻的两个点\(u,v\)之间\(v\)要么为\(u\)的儿子,要么为\(u\)某个祖先的儿子,若\(v\)的\(bfs\)序大于\(u\)的,那么它们之间之多存在一个断点
④在③中确定的限制区间内,如果包含②中确定的断点,那么就可以确定其余点一定不分层。否则区间内点的顺序一定与\(dfs\)序一样,由于区间端点\(dfs\)序中相邻,所以这个区间只可能限制了一个断点
综上:
①若\(bfs\)序中相邻的在\(dfs\)序中逆序,必有断点
②\(dfs\)序中相邻的在\(bfs\)序中正序,之间最多一个断点,要么已确定期望\(1\)个,要么就只有一个不确定,期望\(0.5\)个
③\(1\)只有必有断点
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int using namespace std; const int maxn = 200005,maxm = 100005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } int dfs[maxn],bfs[maxn],pos[maxn],id[maxn],x[maxn],sum[maxn],D[maxn],n; int main(){ n = read(); REP(i,n) dfs[i] = read(); REP(i,n) bfs[i] = read(),id[bfs[i]] = i; REP(i,n) dfs[i] = id[dfs[i]],pos[dfs[i]] = i; x[1] = 1; for (int i = 2; i < n; i++) if (pos[i] > pos[i + 1]) x[i] = 1; for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + x[i]; for (int i = 1; i < n; i++) if (dfs[i] < dfs[i + 1]){ if (sum[dfs[i + 1] - 1] - sum[dfs[i] - 1]){ D[dfs[i]]++; D[dfs[i + 1]]--; } } int tot = 0; for (int i = 1; i < n; i++){ tot += D[i]; if (!x[i] && tot) x[i] = 2; } double ans = 1.0; for (int i = 1; i < n; i++){ if (x[i] == 1) ans += 1.0; else if (!x[i]) ans += 0.5; } printf("%.3lf\n%.3lf\n%.3lf\n",ans - 0.001,ans,ans + 0.001); return 0; }