http://codeforces.com/contest/1474

C. Array Destruction

 

题意:给定一个数组。先选择一个数 x,再从数组中选择两个和为 x 的数,从数组中删去,并 x 变成这两个数中大的那个。问是否可行,以及每一步的选择。

最开始的用来合成 x 的两个数中,必定有一个是数组中最大的数,否则它以后就用不到了。所以只需要再枚举另一个数。

这样就已知 x 与两个数中大的那个数了,之后的每一步就都是可以模拟下去的了。

所以对每一次枚举,O(n)O(n) 模拟进行验证。

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
#include <bits/stdc++.h>
#define debug(x) cout << #x << ":\t" << (x) << endl;
using namespace std;
#define ll long long
#define ull unsigned ll
const int N = 2e7 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const ll inv2 = (mod + 1) / 2;
int T;
int n;
int a[N];
multiset<int, greater<int> >st;
typedef pair<int, int>pii;
vector<pii>vc;
bool ck(int x) {
st.clear();
vc.clear();
for (int i = 1; i <= 2 * n; i++)st.insert(a[i]);
while (!st.empty()) {
int mx = *st.begin();
st.erase(st.begin());
int tmp = x - mx;
auto p = st.find(tmp);
if (p == st.end())return false;
vc.push_back({ tmp,mx });
st.erase(p);
x = mx;
}
return true;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
st.clear();
for (int i = 1; i <= 2 * n; i++)scanf("%d", &a[i]);
sort(a + 1, a + 2 * n + 1, greater<int>());
bool flg = 0;
for (int i = 2; i <= 2 * n; i++) {
if (ck(a[i] + a[1])) {
flg = 1;
puts("YES");
printf("%d\n", a[i] + a[1]);
for (auto p : vc)printf("%d %d\n", p.first, p.second);
break;
}
}
if (!flg)puts("NO");
}
return 0;
}

 

E. What Is It?

 

题意:给定 n,要求构造出一个长度为 n 的排列。对这个排列进行操作,直到这个排列有序,每次操作选择两个位置 i,ji,j,满足 pj=ip_j=i,交换 pi,pjp_i,p_j,代价为 (ji)2(j-i)^2。问使排列有序的最大代价与操作。

构造

从小的开始尝试,大概在 n=4 的时候要猜出构造方法。

下面是 n=6 时。

最后一步是最外层两个交换,倒数第二第三步是1,5交换与2,6交换,倒数第四第五步是1,4交换与3,6交换。

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
#include <bits/stdc++.h>
#define debug(x) cout << #x << ":\t" << (x) << endl;
using namespace std;
#define ll long long
#define ull unsigned ll
const int N = 2e7 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const ll inv2 = (mod + 1) / 2;
int T;
int n;
typedef pair<int, int>pii;
stack<pii>st;
int a[N];
void dfs(int dep) {
if (dep > (n + 1) / 2)return;
if (dep == 1) {
st.push({ 1,n });
swap(a[1], a[n]);
}
else if (dep == (n + 1) / 2) {
int l = n / 2, r = n / 2 + 1;
if (n & 1)st.push({ r,1 }), swap(a[1], a[r]);
else {
st.push({ l,n });
st.push({ r,1 });
swap(a[l], a[n]);
swap(a[r], a[1]);
}
return;
}
else {
st.push({ dep,n });
st.push({ n - dep + 1,1 });
swap(a[dep], a[n]);
swap(a[n - dep + 1], a[1]);
}
dfs(dep + 1);
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
ll ans = 1ll * (n - 1)*(n - 1);
for (int i = 1; i < n / 2; i++) {
ans += 2ll * (n - i - 1)*(n - i - 1);
}
if (n & 1)ans += 1ll * (n / 2)*(n / 2);
for (int i = 1; i <= n; i++)a[i] = i;
dfs(1);
printf("%lld\n", ans);
for (int i = 1; i <= n; i++)printf("%d%c", a[i], " \n"[i == n]);
printf("%d\n", n - 1);
while (!st.empty()) {
printf("%d %d\n", st.top().first, st.top().second);
st.pop();
}
}
return 0;
}