ABC444C AtCoder Riko

c---atcoder-riko">C - AtCoder Riko

1. 题意梗概

给定一个包含 NN 个正整数的序列 AA。这些数字是由若干根长度为 LL 的零食经过摇晃后产生的。每根原始长度为 LL 的零食要么保持完整,要么断成两截(长度和为 LL)。

求所有可能的原始长度 LL。

2. 逻辑推导

这其实是一个构造问题,注意到每个零食只有两种情况,所以我们可以把目光转移到最大值上。

  • 情况一:AmaxA_{max} 是一根完整的零食。那么 L=AmaxL = A_{max}。此时需要验证剩下的所有元素能否两两配对成 AmaxA_{max}。

  • 情况二:AmaxA_{max} 也是断裂后的碎片之一。这意味着没有任何一根零食是完整的。此时,AmaxA_{max} 必须与序列中最小的元素 AminA_{min} 配对。即 L=Amin+AmaxL = A_{min} + A_{max}。

因此,可能的 LL 只有两个可能得情况。我们只需对这两个值分别进行 O(N)O(N) 的双指针配对检验即可。

3. 代码实现

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
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int maxn = 3e5 + 50;

set< ll > res;

ll a[maxn];
int n;

bool check( int x )
{
vector< int > tmp;
for( int i = 1; i <= n; ++ i )
{
if( a[i] < x ) tmp.push_back( a[i] );
}

if( tmp.size( ) % 2 == 1 ) return 0;

int l = 0, r = tmp.size( ) - 1;
while( l < r )
{
if( tmp[l] + tmp[r] != x ) return 0;
l ++, r --;
}

res.insert( x );
return 1;
}

void solve( )
{
cin >> n;
ll sum = 0;
for( int i = 1; i <= n; ++ i ) cin >> a[i], sum += a[i];
sort( a + 1, a + n + 1 );

int minv = a[1], maxv = a[n];

check( maxv );

check( minv + maxv );

for( int ans : res ) cout << ans << ' ';

}

int main( )
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
solve( );
return 0;
}

ABC444C AtCoder Riko
http://miqiu.space/posts/f53b0091/
作者
Miqiu
发布于
2026年2月7日
许可协议