E. New Year and the Acquaintance Estimation
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Bob is an active user of the social network Faithbug. On this network, people are able to engage in a mutual friendship. That is, if a is a friend of b, then b is also a friend of a. Each user thus has a non-negative amount of friends.
This morning, somebody anonymously sent Bob the following link: graph realization problem and Bob wants to know who that was. In order to do that, he first needs to know how the social network looks like. He investigated the profile of every other person on the network and noted down the number of his friends. However, he neglected to note down the number of his friends. Help him find out how many friends he has. Since there may be many possible answers, print all of them.
Input
The first line contains one integer n (1≤n≤5⋅105), the number of people on the network excluding Bob.
The second line contains n numbers a1,a2,…,an (0≤ai≤n), with ai being the number of people that person i is a friend of.
Output
Print all possible values of an+1 — the amount of people that Bob can be friend of, in increasing order.
If no solution exists, output −1.
Examples
inputCopy
3
3 3 3
outputCopy
3
inputCopy
4
1 1 1 1
outputCopy
0 2 4
inputCopy
2
0 2
outputCopy
-1
inputCopy
35
21 26 18 4 28 2 15 13 16 25 6 32 11 5 31 17 9 3 24 33 14 27 29 1 20 4 12 7 10 30 34 8 19 23 22
outputCopy
13 15 17 19 21
Note
In the first test case, the only solution is that everyone is friends with everyone. That is why Bob should have 3 friends.
In the second test case, there are three possible solutions (apart from symmetries):
a is friend of b, c is friend of d, and Bob has no friends, or
a is a friend of b and both c and d are friends with Bob, or
Bob is friends of everyone.
The third case is impossible to solve, as the second person needs to be a friend with everybody, but the first one is a complete stranger.
好题。来源自CF的goodbye2018专场,这是第一场参加人数超过一万人的比赛。前面都很顺利,唯独被这题难倒了,好在rating没有掉。
当时脑抽地没有点开题目里的链接提示,导致思路绕了一个大弯。后来写来写去问题也越来越多。题目中提示了Graph realization problem中的一个重要定理Erdős–Gallai theorem

(其中d是度序列从大到小排完序产生的序列)
这个定理告诉了我们,当奇偶性不矛盾的时候,一个度序列是否存在对应图的充要条件(类似的定理还有Havel–Hakimi algorithm,也非常重要,它还告诉了我们构造对应图的方法)。
显然如果有对应图,度序列必须满足这个条件,可以理解为任意的前k个点的度至少能被后面的点的度凑齐。但充分性不是很好证明,可能需要离散数学的知识。
知道这个定理之后,我们发现,对随着Bob的度x有两种约束,一种是x在不等式左边的上界约束,一种是x在不等式右边的下界约束。随着x的增大,x在d中的位置会逐渐靠前,于是上界约束多了,下界约束少了。想象一下所有上界约束的最小值H和所有下界最大值L关于x的函数图像,可以知道这是两条不递增的折线。而直线y=x和两条折线相交于两点,那么这两点之间的x取值就是答案了。
因此我们得到了一个重要信息,答案如果存在,必然是一段间隔为2的连续序列。而答案不存在的情况,相当于是y=x与H的交点落在和L的交点的左边。
而求上界和下界,我们可以采用两次二分答案的方式。对于假定的答案x,进行check,采用桶法维护后缀中d和k的最小值的和,可以把每次check的效率下降到O(n),当然,具体实现有非常多细节(我也忘了好多QwQ),不多叙述,不等式的化简也千奇百怪,每个人有每个人的方法。下面是我的代码
#include<cstdio>
#include<algorithm>
#include<functional>
using namespace std;
using LL=long long;
int a[500005],n,x,y,odd,h[500005];
LL sum[500005],suf[500005];
void array_init()
{
for(int i=1;i<=n;i++)
h[i]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i],h[a[i]]++;
for(int i=1;i<=n;i++)
h[i]+=h[i-1];
LL cnt;
for(int i=1;i<=n;i++)
{
cnt=max(n-i-h[i],0);
suf[i]=cnt*i+sum[n]-sum[i+cnt];
}
}
bool low_check(int x) //具体的化简需要一阵子推导
{
for(int j=1;j<=n&&a[j]>=x;j++)
if(x<sum[j]-(LL)j*(j-1)-suf[j])
return false;
return true;
}
bool up_check(int x) //具体的化简需要一阵子推导
{
for(int j=n;j>0&&a[j+1]<x;j--)
if(x>(LL)j*(j+1)+suf[j]-sum[j]+max(n-j-h[j],0))
return false;
return true;
}
int low_bound()
{
int L=odd,R=(n&1)^odd?n-1:n,M;
while(L<R)
{
M=L+R>>1;
M=(M&1)^odd?M-1:M;
if(low_check(M))
R=M;
else
L=M+2;
}
return L;
}
int up_bound()
{
int L=odd,R=(n&1)^odd?n-1:n,M;
while(L<R)
{
M=L+R+1>>1;
M=(M&1)^odd?M+1:M;
if(up_check(M))
L=M;
else
R=M-2;
}
return L;
}
bool check() //这个check是针对min(d[i],k)中不仅d[i]要满足不等号,k也要满足,所以事先check保证给的序列本身不自相矛盾。当然这一步也可以放在二分的时候check,不过不是很清晰。
{
for(int i=1;i<=n;i++)
if(i<sum[i]-(LL)i*(i-1)-suf[i])
return false;
return true;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),odd^=a[i]&1;
sort(a+1,a+n+1,greater<int>());
array_init();
if(!check())
{
printf("-1");
return 0;
}
x=low_bound();
y=up_bound();
if(x>y)
{
printf("-1");
return 0;
}
for(int i=x;i<=y;i+=2)
printf("%d ",i);
return 0;
}
另外本题还有另一种方法,不用二分,每次从小到大枚举x,再用logn的时间修改不等式约束,但实现起来不是很容易。

本文深入探讨了Codeforces上一道名为“New Year and the Acquaintance Estimation”的社交网络图论难题,通过分析Erdős–Gallai定理,提供了一种使用二分搜索和桶法维护后缀信息的有效解决方案。
224

被折叠的 条评论
为什么被折叠?



