嫌疑人

题目大意:每人可以投两个,boss说A和B是嫌疑人,但是会参考在场人们的建议.要至少p个人通过才能实施.(同意的条件:A或者B是这个人投的其中一个),问有多少种合法的无序方案

我们枚举其中一个,然后对另一个删边,减贡献,然后加上预处理好的后缀和

deg[i]表示i这个人被指定了多少次.

f[i]的含义只可意会,我第一次意识到我词穷了...

就是我们考虑选的这个点之后,我们把所有与这个点连边的点暂时全删了

把所有当前度数为delta(也就意味着当这个点与x不连之后,将没有贡献)的点统计答案

实在是一个思维好题

代码如下:

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>
#define int long long
#define ll long long
using namespace std;

const int N = 3e5 + 66;

int ver[N << 1], nex[N << 1], head[N], cnt;

inline void add_edge(int x, int y)
{
ver[++ cnt] = y;
nex[cnt] = head[x];
return (void)(head[x] = cnt);
}

int n, p, res;
int deg[N], f[N];

signed main()
{
int i, x, y;
n = read(), p = read();
for (i = 1; i <= n; ++ i)
{
x = read(), y = read();
add_edge(x, y), add_edge(y, x);
++ deg[x], ++ deg[y];
}
for (i = 1; i <= n; ++ i) ++ f[deg[i]];
for (i = n; i >= 1; -- i) f[i] += f[i + 1];
for (x = 1; x <= n; ++ x)
{
int delta = p - deg[x];
if (delta <= 0) res += n - 1;
else
{
int k(0);
if (deg[x] >= delta) ++ k;
for (i = head[x]; i; i = nex[i])
{
y = ver[i];
if (deg[y] == delta) ++ k;
-- deg[y];
}
res += f[delta] - k;
for (i = head[x]; i; i = nex[i])
{
y = ver[i];
++ deg[y];
}
}
}
put(res / 2);
return 0;
}

后记:

傻逼std还用树状数组来维护...可恶!当时搞得我那么懵逼

细细想来一点也不难.