欢迎神犇吊打|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2023-03-08 21:55阅读: 38评论: 0推荐: 0

CF985G Team Players

CF985G Team Players

Luogu CF985C

题面翻译

n 个点,编号依次为 0,1....n1

如果一个三元组 (i,j,k) (i<j<k) 两两没有边相连,那么它的贡献为 Ai+Bj+Ck

求出所有三元组的贡献和,答案对 264 取模。

题目描述

There are n players numbered from 0 to n1 with ranks. The i -th player has rank i .

Players can form teams: the team should consist of three players and no pair of players in the team should have a conflict. The rank of the team is calculated using the following algorithm: let i , j , k be the ranks of players in the team and i<j<k , then the rank of the team is equal to Ai+Bj+Ck .

You are given information about the pairs of players who have a conflict. Calculate the total sum of ranks over all possible valid teams modulo 264 .

输入格式

The first line contains two space-separated integers n and m ( 3n2105 , 0m2105 ) — the number of players and the number of conflicting pairs.

The second line contains three space-separated integers A , B and C ( 1A,B,C106 ) — coefficients for team rank calculation.

Each of the next m lines contains two space-separated integers ui and vi ( 0ui,vi<n,uivi ) — pair of conflicting players.

It's guaranteed that each unordered pair of players appears in the input file no more than once.

输出格式

Print single integer — the total sum of ranks over all possible teams modulo 264 .

样例 #1

样例输入 #1

4 0
2 3 4

样例输出 #1

64

样例 #2

样例输入 #2

4 1
2 3 4
1 0

样例输出 #2

38

样例 #3

样例输入 #3

6 4
1 5 3
0 3
3 5
5 4
4 3

样例输出 #3

164

提示

In the first example all 4 teams are valid, i.e. triples: {0, 1, 2}, {0, 1, 3}, {0, 2, 3} {1, 2, 3}.

In the second example teams are following: {0, 2, 3}, {1, 2, 3}.

In the third example teams are following: {0, 1, 2}, {0, 1, 4}, {0, 1, 5}, {0, 2, 4}, {0, 2, 5}, {1, 2, 3}, {1, 2, 4}, {1, 2, 5}.

Solution

两两不连边不好计算,考虑容斥,分为所有三元组、至少有一条边相连的、至少有两条边相连的、至少有三条边相连的。

第四种很好计算,直接套三元环计数板子即可,考虑剩余的如何计算。

由于笔者习惯,以下所有节点编号改为 [1,n],因此在计算对答案的贡献的时候会 1

  • 所有三元组 (x,y,z)

    枚举 i[1,n],分讨 i 在三元组中的位置:

    • x=i:此时 y,z 只需要满足大于 x,因此对答案贡献 A(ni)(ni1)2(i1)
    • y=i:此时 x[1,y)z(y,n],因此对答案贡献 B(i1)(ni)(i1)
    • z=i:此时 x,y 只需要满足小于 z,因此对答案贡献 C(i1)(i2)2(i1)
  • 至少有一条边相连:

    枚举所有边 uv,不妨设 u<v,考虑分讨第三个元素 tu,v 的大小关系:

    • x=u:此时只需要 t>x,因此对答案贡献为 A(u1)(nu1)
    • y=u:此时只需要 t<x,因此对答案贡献为 B(u1)(u1)
    • y=v:此时只需要 t>y,因此对答案贡献为 B(v1)(nv)
    • z=v:此时只需要 t<y,因此对答案贡献为 C(v1)(v2)
    • x=t:此时 t[1,u),利用等差数列求和公式得到贡献为 A(u1)(u2)2
    • y=t:此时 t(u,v),同理得到贡献为 B(u+v2)(vu1)2
    • z=t:此时 t(v,n],贡献为 C(n+v1)(nv)2
  • 至少有两条边相连:

    考虑枚举每个点的出边,先将出边按照到达节点的编号排序。设当前枚举的节点是 u,到达的节点为 v,在 u 的所有可到达节点中排名第 iu 所有可到达的节点个数为 tn。分讨一下 u,v 的大小关系,设第三个元素的编号为 t

    • v<u

      • t<v,则 v 对答案贡献 A(v1)(tni1)
      • t>v,则 v 对答案贡献 B(v1)(i1)
    • v>u

      • t<v,则 v 对答案贡献 C(v1)(i2)
      • t>v,则 v 对答案贡献 B(v1)(tni)

    对于 u 对答案的贡献,也进行分讨:

    • x=u:此时为 t,v>u,贡献为 A(tni)(tni1)2(u1)
    • y=u:此时 t,v 分居 u 两侧,贡献为 B(tni)(i1)(u1)
    • z=u:此时 t,v<u,贡献为 C(i1)(i2)2(u1)

分讨完了过后将所有情况乘上容斥系数加起来即是答案。

#include<bits/stdc++.h>

using namespace std;
using ui64 = unsigned long long;

int n, m;
ui64 A, B, C;
ui64 ans = 0;
constexpr int _N = 2e5 + 5;
vector<int> oe[_N], ne[_N];
int deg[_N], fr[_N], to[_N];

ui64 GetAns1() {
	ui64 sum = 0;
	
	for (int X = 1; X <= n; ++X)
		for (int Y : ne[X]) {
			int x = min(X, Y), y = max(X, Y);
			sum += A * (x - 1) * (n - x - 1);
			sum += B * (x - 1) * (x - 1);
			sum += B * (y - 1) * (n - y);
			sum += C * (y - 1) * (y - 2);
			sum += A * (x - 1) * (x - 2) / 2;
			sum += B * (y + x - 2) * (y - x - 1) / 2;
			sum += C * (n + y - 1) * (n - y) / 2;
		}
	
	return sum;
}

ui64 GetAns2() {
	ui64 sum = 0;
	
	for (int X = 1; X <= n; ++X) {
		oe[X].emplace_back(X);
		sort(oe[X].begin(), oe[X].end());
		int tn = oe[X].size() - 1;
		
		for (int i = 0; i <= tn; ++i) {
			int Y = oe[X][i];
			
			if (Y != X) {
				if (Y < X) {
					sum += A * (Y - 1) * (tn - i - 1);
					sum += B * (Y - 1) * i;
				} else {
					sum += B * (Y - 1) * (tn - i);
					sum += C * (Y - 1) * (i - 1);
				}
			} else {
				sum += A * (tn - i) * (tn - i - 1) / 2 * (X - 1);
				sum += B * i * (tn - i) * (X - 1);
				sum += C * i * (i - 1) / 2 * (X - 1);
			}
		}
	}
	
	return sum;
}

int vis[_N];

ui64 GetAns3() {
	ui64 sum = 0;
	
	for (int X = 1; X <= n; ++X) {
		for (int Y : ne[X]) vis[Y] = X;
		
		for (int Y : ne[X]) for (int Z : ne[Y]) {
			if (vis[Z] != X) continue;
			
			int t[] = {X, Y, Z};
			sort(t, t + 3);
			sum += (t[0] - 1) * A + (t[1] - 1) * B + (t[2] - 1) * C;
		}
	}
	
	return sum;
}

ui64 GetAll() {
	ui64 sum = 0;
	
	for (int i = 1; i <= n; ++i) {
		sum += A * (n - i) * (n - i - 1) / 2 * (i - 1);
		sum += B * (i - 1) * (n - i) * (i - 1);
		sum += C * (i - 1) * (i - 2) / 2 * (i - 1);
	}
	
	return sum;
}

signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> m >> A >> B >> C;
	
	for (int i = 1; i <= m; ++i) {
		cin >> fr[i] >> to[i]; ++fr[i], ++to[i];
		oe[fr[i]].emplace_back(to[i]);
		oe[to[i]].emplace_back(fr[i]);
		++deg[fr[i]], ++deg[to[i]];
	}
	
	for (int i = 1; i <= m; ++i) {
		int x = fr[i], y = to[i];
		
		if (deg[x] > deg[y] || (deg[x] == deg[y] && x > y)) swap(x, y);
		
		ne[x].emplace_back(y);
	}
	
	ui64 all = 0, sum = 0;
	all = GetAll();
	sum = GetAns1() - GetAns2() + GetAns3();
	cout << all - sum << '\n';
}
posted @   Hanx16Msgr  阅读(38)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起