嫌疑人
题目大意:每人可以投两个,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
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还用树状数组来维护...可恶!当时搞得我那么懵逼
细细想来一点也不难.