[AtCoder]NIKKEI Programming Contest 2019-2 C

题目链接:

题目链接

题意简述:

给定两个长度均为$n$的序列$A,B$

定义一次操作为:交换$A_i, A_j$,其中$i in [1, n], j in [1, n]$且$i neq j$

问是否能使用小于等于$n - 2$次操作,使得:$forall i in [1, n]$,总有$A_i leq B_i$?

其中$1 le n le 100, 000$

简要做法:

特别巧妙的一道题。

设排序后的数组分别为$A’$和$B’$,那么:

如果$exists i, j$满足$A’_i > B’_j$,那么一定是不可行的;

如果$exists i$满足$A’_i le B’_{i+1}$,那么一定是可行的。

排除了上述两种特殊情况后,考虑构建一个图:

对于$A$中的任意一个数$A_i$,设其在$A’$中的排名为$rank(A, i)$,

那么连一条$A_i to B_j$的边,其中$j$满足:$rank(B, j) = rank(A, i)$

显然这样会形成至少一个环,其中每条边$A_i to B_j$表示应该交换$A_i, A_j$

环的总长度就为交换次数,

那么如果只有一个环,就有$n - 1$条边,无法满足题意;

如果有多于一个的环,就有小于等于$n - 2$条边,满足题意。

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

#define ll long long
#define rgi register int
#define rgl register long long
#define il inline

const int N = 2e5 + 10;

int n, tot, cnt, num[N], nxt[N], vis[N];
int a[N], sortA[N], rankA[N];
int b[N], sortB[N], posB[N];

il int () {
rgi x = 0, f = 0, ch;
while(!isdigit(ch = getchar())) f |= ch == 大专栏  [AtCoder]NIKKEI Programming Contest 2019-2 C - Swapsn class="string">'-';
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}

int main() {
n = read();
for(rgi i = 1; i <= n; ++i) a[i] = num[++tot] = read();
for(rgi i = 1; i <= n; ++i) b[i] = num[++tot] = read();

std::sort(num + 1, num + tot + 1);
tot = std::unique(num + 1, num + tot + 1) - (num + 1);
for(rgi i = 1; i <= n; ++i) a[i] = std::lower_bound(num + 1, num + tot + 1, a[i]) - (num + 1) + 1;
for(rgi i = 1; i <= n; ++i) b[i] = std::lower_bound(num + 1, num + tot + 1, b[i]) - (num + 1) + 1;


for(rgi i = 1; i <= n; ++i) sortA[i] = a[i];
for(rgi i = 1; i <= n; ++i) sortB[i] = b[i];
std::sort(sortA + 1, sortA + n + 1);
std::sort(sortB + 1, sortB + n + 1);
//Smallest Permutation

for(rgi i = 1; i <= n; ++i) if(sortA[i] > sortB[i]) {
puts("No");
return 0;
}
for(rgi i = 1; i <= n - 1; ++i) if(sortA[i + 1] <= sortB[i]) {
puts("Yes");
return 0;
}
//Exclusion

for(rgi i = 1; i <= n; ++i) posB[b[i]] = i;
//pos in b[]

for(rgi i = 1; i <= n; ++i) rankA[sortA[i]] = i;
//rank in a[]

for(rgi i = 1; i <= n; ++i) nxt[i] = posB[sortB[rankA[a[i]]]];
//Add edges

for(rgi i = 1; i <= n; ++i) if(!vis[i]) {
int cur = i;
do {
vis[cur] = 1;
cur = nxt[cur];
} while(!vis[cur]);
cnt++;
}

puts(cnt == 1 ? "No" : "Yes");

return 0;
}
原文地址:https://www.cnblogs.com/lijianming180/p/12409397.html