您的位置:首页 > 其它

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

3

7 8 5 6 1 2 4 3

Sample Output

6

HINT

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: