bzoj3990: [SDOI2015]排序 dfs 数学
2018-01-23 07:54
337 查看
bzoj3990: [SDOI2015]排序
Description
小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到右划分为2^{N-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换其中两段.小A想知道可以将数组A从小到大排序的不同的操作序列有多少个,小A认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).下面是一个操作事例:
N=3,A[1..8]=[3,6,1,2,7,8,5,4].
第一次操作,执行第3种操作,交换A[1..4]和A[5..8],交换后的A[1..8]为[7,8,5,4,3,6,1,2].
第二次操作,执行第1种操作,交换A[3]和A[5],交换后的A[1..8]为[7,8,3,4,5,6,1,2].
第三次操作,执行第2中操作,交换A[1..2]和A[7..8],交换后的A[1..8]为[1,2,3,4,5,6,7,8].
Input
第一行,一个整数N第二行,2^N个整数,A[1..2^N]
Output
一个整数表示答案Sample Input
37 8 5 6 1 2 4 3
Sample Output
6HINT
100%的数据, 1<=N<=12.分析
很神的一道搜索题。首先可以想到的是这里的每一个操作都是独立存在的,所以操作的顺序不影响答案。也就是对于一个长度为n的操作序列,对答案的贡献是n!
接下来我们考虑每一步。对于操作i,它唯一可以做到的是调整2n−i段区间长度为2i的区间内部顺序(因为它可以交换2n−i+1段长度为2i−1的区间)
并且只有这个操作可以调整,如果过了这个操作别的操作都无法调换这2n−i段区间长度为2i的区间内部顺序。这就是所有操作“互不影响”,“独立存在”的含义。
那么对于一次操作,我们考虑它可调整的区间需要满足的条件。
如果有两个以上的区间需要调整,那么由于我们只能交换一次,所以不合法。
如果没有区间需要调整我们直接往下做
如果只有一个区间需要调整,我们调整这个区间的内部顺序,继续往下做。
如果有两个区间需要调整,我们枚举四种交换方法,如果有方法合法,就往下做(好像只有一种是合法的)
讨论一下就是dfs咯。
代码
/************************************************************** Problem: 3991 User: 2014lvzelong Language: C++ Result: Accepted Time:6848 ms Memory:11924 kb ****************************************************************/ #include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<functional> #include<queue> #include<set> using namespace std; const int N = 110000; int read() { char ch = getchar(); int x = 0, f = 1; while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();} return x * f; } int nxt[N << 1], to[N << 1], w[N << 1], pre , dson , siz , deep , f , d , pos , in , top, tot, n, m; long long h , ans; bool vis ; set<int>s; void add(int u, int v, int ww) {to[++top] = v; nxt[top] = pre[u]; w[top] = ww; pre[u] = top;} void adds(int u, int v, int w) {add(u, v, w); add(v, u, w);} void dfs1(int u) { siz[u] = 1; dson[u] = 0; for(int i = pre[u]; i; i = nxt[i]) if(to[i] != f[u]) { f[to[i]] = u; deep[to[i]] = deep[u] + 1; h[to[i]] = h[u] + w[i]; dfs1(to[i]); siz[u] += siz[to[i]]; if(siz[to[i]] > siz[dson[u]]) dson[u] = to[i]; } } void dfs2(int u, int chain) { d[u] = chain; pos[in[u] = ++tot] = u; if(!dson[u]) return; dfs2(dson[u], chain); for(int i = pre[u]; i; i = nxt[i]) if(to[i] != f[u] && to[i] != dson[u]) dfs2(to[i], to[i]); } int lca(int u, int v) { while(d[u] != d[v]) { if(deep[d[u]] < deep[d[v]]) swap(u, v); u = f[d[u]]; } return deep[u] > deep[v] ? v : u; } long long dist(int u, int v) {return h[u] + h[v] - (h[lca(u, v)] << 1);} int pr(int x) { set<int>::iterator it = s.find(in[x]); return it == s.begin() ? 0 : pos[*--it]; } int ne(int x) { set<int>::iterator it = s.find(in[x]); return ++it == s.end() ? 0 : pos[*it]; } void Ins(int x) { s.insert(in[x]); int l = pr(x), da0a r = ne(x); if(l) ans += dist(l, x); if(r) ans += dist(r, x); if(l && r) ans -= dist(l, r); } void Del(int x) { int l = pr(x), r = ne(x); if(l) ans -= dist(l, x); if(r) ans -= dist(r, x); if(l && r) ans += dist(l, r); s.erase(in[x]); } int main() { n = read(); m = read(); for(int i = 1;i < n; ++i) { int u = read(), v = read(), w = read(); adds(u, v, w); } dfs1(1); dfs2(1, 1); while(m--) { int x = read(); if(!vis[x]) Ins(x); else Del(x); vis[x] ^= 1; printf("%lld\n", s.size() ? ans + dist(pos[*s.begin()], pos[*--s.end()]) : 0); } return 0; }
相关文章推荐
- BZOJ3990 [SDOI2015]排序 【搜索】
- bzoj 3990: [SDOI2015]排序 dfs
- bzoj3990 [SDOI2015]排序 dfs
- BZOJ 3990 Sdoi2015 排序 DFS
- 【bzoj3990】【SDOI2015】【排序】【dfs】
- bzoj3990[SDOI2015]排序
- 【bzoj3990】[SDOI2015]排序 DFS
- [BZOJ3990][SDOI2015]排序(DFS)
- BZOJ3990:[SDOI2015]排序——题解
- BZOJ.3990.[SDOI2015]排序(DFS)
- [SDOI 2015] 排序
- 【SDOI2015】【BZOJ3990】排序
- 数学(快速数论变换):SDOI2015 序列统计
- [BZOJ 3994][SDOI 2015]约数个数 数学+反演
- 【SDOI2015】bzoj3990 排序
- bzoj3990【SDOI2015】排序
- BZOJ 3990 [SDOI2015] 排序
- 搜索——BZOJ3990/Luogu3322 [SDOI2015]排序
- [SDOI2015][BZOJ3990] 排序
- 【dfs序】【set】bzoj3991 [Sdoi2015]寻宝游戏