Link
HDU - http://acm.hdu.edu.cn/showproblem.php?pid=5873
Description
有
m
m
m 个组,每一组有
n
n
n 支队伍。
每一组队伍中,任意两支队伍之间都会进行一场比赛。
一场比赛中,赢的队伍得两分,输的队伍不得分,如果平局则两队各加一分。
给出所有队伍的最终得分,判定是否合法。
∑
s
c
o
r
e
=
n
(
n
−
1
)
\sum score=n(n\pmb{-}1)
∑score=n(n−−−1) ……就可以了吗?当然不是(、
考虑:可以判断分数为奇数的队伍个数是否为偶数
还可以判断每个队伍最终分数是否大于
2
(
n
−
1
)
2(n\pmb{-}1)
2(n−−−1)
还还可以判断最终分数大于
2
⌊
n
−
1
2
⌋
2\lfloor\frac{n\pmb{-}1}{2}\rfloor
2⌊2n−−−1⌋ 的队伍个数是否多于一半
还还还可以………………
……不过也不一定能够对。
考虑一点别的东西?
比如说复杂度(
那只有两种可能,一种是枚举分数,一种是枚举队伍
然后其实都是枚举队伍……(
队伍顺序没有影响,那为了方便干脆排个序,然后就既枚举了分数又枚举了队伍(?
显然我们不会对着单个分数考虑什么东西
那么我们对排序之后的队伍考虑一下?……至于排序的复杂度嘛,桶排不就不会炸了
排序完之后,考虑从小到大分数第
i
i
i 大的队伍
首先容易知道的是,分数最大的队伍的分数至少是
n
−
1
n-1
n−1 ,至多是
2
(
n
−
1
)
2(n-1)
2(n−1)
分数最小的队伍的分数至少是
0
0
0 ,至多是
n
−
1
n-1
n−1
分数第二少的队伍的分数至少是?
0
0
0 ?不对吧……因为有得分最少的队伍垫底,所以至少是
1
1
1
第三少的至少是
2
2
2 依次类推
但是平局的话,之前确定的得分最少的队伍的得分就可能变多,那么好像还有点事情可以搞
灵感:考虑后面的时候会对前面造成影响→是否能把前面的影响也继续算下去
后面变少前面变多+限制至少/至多→前缀和
分数第一少加分数第二少 最少为
2
2
2 最多为
2
(
n
−
1
)
2(n-1)
2(n−1)
分数第一少加第二少加第三少 最少为
6
6
6 最多仍然是
3
(
n
−
1
)
3(n-1)
3(n−1)
然后发现 每次最少都是
i
(
i
−
1
)
i(i-1)
i(i−1) (你考虑最少的那几个组成的环,显然),最多是
i
(
n
−
1
)
i(n-1)
i(n−1)
(最多的限制其实没什么用……你可以用判断每个点的分数是否超过
2
(
n
−
1
)
2(n-1)
2(n−1) 代替
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = 20005;
int Buk[MAXN];
int Rep[MAXN];
int main() {
register int M, B, p, t, mxt, tot;
register bool fail = 0;
while(~scanf("%d",&M))
{
while(M--)
{
fail = 0; t = mxt = tot = 0;
scanf("%d", &B);
for (register int i = 1; i <= B; ++i)
{
scanf("%d", &p);
++Buk[p];
mxt = max(mxt, p);
}
for (register int i = 0; i <= mxt; ++i)
{
while (Buk[i])
{
if(!fail) {
++tot;
t += i;
if (t < tot * (tot - 1) || t > tot * (B - 1)) fail = 1;
}
--Buk[i];
}
}
putchar(fail?'F':'T'); putchar('\n');
}
}
return 0;
}
Landau’s Theorem
把一个
n
n
n 点图的所有点按照出度排序
那么这个图是竞赛图当且仅当:排序后前
i
i
i 个点出度前缀和
≥
k
(
k
−
1
)
2
\ge \frac{k(k-1)}{2}
≥2k(k−1) ,且
k
=
n
k=n
k=n 的时候取等号