题目 | ± Increasing Sequence
AtCoder Regular Contest 153
C - ± Increasing Sequence
https://atcoder.jp/contests/arc153/tasks/arc153_c
Problem Statement
You are given a sequence of length $N$, $A = (A_1, \ldots, A_N)$, consisting of $1$ and $-1$.
Determine whether there is an integer sequence $x = (x_1, \ldots, x_N)$ that satisfies all of the following conditions, and print one such sequence if it exists.
- $|x_i| \leq 10^{12}$ for every $i$ ($1\leq i\leq N$).
- $x$ is strictly increasing. That is, $x_1 < \cdots < x_N$.
- $\sum_{i=1}^N A_ix_i = 0$.
Constraints
- $1\leq N\leq 2\times 10^5$
- $A_i \in \lbrace 1, -1\rbrace$
Input
The input is given from Standard Input in the following format:
$N$
$A_1$ $\ldots$ $A_N$
Output
If there is an integer sequence $x$ that satisfies all of the conditions in question, print Yes
; otherwise, print No
. In case of Yes
, print the elements of such an integer sequence $x$ in the subsequent line, separated by spaces.
$x_1$ $\ldots$ $x_N$
If multiple integer sequences satisfy the conditions, you may print any of them.
Sample Input 1
5
-1 1 -1 -1 1
Sample Output 1
Yes
-3 -1 4 5 7
For this output, we have $\sum_{i=1}^NA_ix_i= -(-3) + (-1) - 4 - 5 + 7 = 0$.
Sample Input 2
1
-1
Sample Output 2
Yes
0
Sample Input 3
2
1 -1
Sample Output 3
No
题解
这道题很明显是一道构造题,构造题解法往往有挺多的,不过只要能把答案凑出来就行。我的构造思路是:
- 直接用 $x_i=i$ 作为初始解,算出 $sum=\sum_{i=1}^N A_ix_i$
- 如果 $sum>0$ 那么想办法让 $sum$ 减小为 $0$
- 如果 $sum<0$ 那么想办法让 $sum$ 增大为 $0$
于是,解题核心就在于如何调整 $sum$ 的大小。
由于这两种情况完全对称,我们只以 $sum>0$,要减小 $sum$ 为例,另一种情况同理。
对于我们的初始解,有两种操作能保证操作后仍然符合严格单调递增:
- 将第 $k,k+1,\dots,N$ 位同时增大 $t$($k,t\in\mathbb{Z}\ 且\ 1\leq k\leq N$)
- 将第 $1,2,\dots,k$ 位同时减小 $t$($k,t\in\mathbb{Z}\ 且\ 1\leq k\leq N$)
那么我们就用这两种操作来控制 $sum$ 的大小。
对于第一种操作,若第 $k,k+1,\dots,N$ 位的 $-1$ 的数量比 $1$ 的数量正好多一个,那么我们将其增大 $t$,则 $sum$ 减小 $t$.
对于第二种操作,若第 $1,2,\dots,k$ 位的 $1$ 的数量比 $-1$ 的数量正好多一个,那么我们将其减小 $t$,则 $sum$ 减小 $t$.
这样,只要我们能找到满足两种操作其中一种的 $k$,我们就可以通过增大(减小)后缀(前缀)来任意调整 $sum$ 的大小,当然就可以将 $sum$ 调整为 $0$. 最后通过 $k,t$ 计算得到最终的解即可,即:
$$ 1,2,\dots,k-1,k+t,k+1+t,\dots,N-1+t,N+t(第一种操作)\\ 或者\\ 1-t,2-t,\dots,k-1-t,k-t,k+1,\dots,N-1,N(第二种操作) $$
如果我们两种操作都找不到满足条件的 $k$,那么就说明这种情况无解,输出 No
即可。
代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int N;
cin >> N;
vector<int> A(N + 1);
for (int i = 1; i <= N; i++)
cin >> A[i];
int sum = 0;
for (int i = 1; i <= N; i++)
sum += A[i] * i;
if (sum > 0)
{
int cnt_posi = 0, cnt_nega = 0, pos = 0;
for (int i = N; i >= 1; i--)
{
if (A[i] == 1)
cnt_posi++;
else
cnt_nega++;
if (cnt_nega > cnt_posi)
{
pos = i;
break;
}
}
if (pos)
{
cout << "Yes" << endl;
for (int i = 1; i < pos; i++)
cout << i << ' ';
for (int i = pos; i <= N; i++)
cout << i + sum << ' ';
cout << endl;
return 0;
}
cnt_posi = 0, cnt_nega = 0;
for (int i = 1; i <= N; i++)
{
if (A[i] == 1)
cnt_posi++;
else
cnt_nega++;
if (cnt_posi > cnt_nega)
{
pos = i;
break;
}
}
if (pos)
{
cout << "Yes" << endl;
for (int i = 1; i <= pos; i++)
cout << i - sum << ' ';
for (int i = pos + 1; i <= N; i++)
cout << i << ' ';
cout << endl;
return 0;
}
}
else
{
int cnt_posi = 0, cnt_nega = 0, pos = 0;
for (int i = N; i >= 1; i--)
{
if (A[i] == 1)
cnt_posi++;
else
cnt_nega++;
if (cnt_nega < cnt_posi)
{
pos = i;
break;
}
}
if (pos)
{
cout << "Yes" << endl;
for (int i = 1; i < pos; i++)
cout << i << ' ';
for (int i = pos; i <= N; i++)
cout << i - sum << ' ';
cout << endl;
return 0;
}
cnt_posi = 0, cnt_nega = 0;
for (int i = 1; i <= N; i++)
{
if (A[i] == 1)
cnt_posi++;
else
cnt_nega++;
if (cnt_posi < cnt_nega)
{
pos = i;
break;
}
}
if (pos)
{
cout << "Yes" << endl;
for (int i = 1; i <= pos; i++)
cout << i + sum << ' ';
for (int i = pos + 1; i <= N; i++)
cout << i << ' ';
cout << endl;
return 0;
}
}
cout << "No" << endl;
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi