CF985G Team Players
CF985G Team Players
题面翻译
有
如果一个三元组
求出所有三元组的贡献和,答案对
题目描述
There are
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
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
输入格式
The first line contains two space-separated integers
The second line contains three space-separated integers
Each of the next
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
样例 #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
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
两两不连边不好计算,考虑容斥,分为所有三元组、至少有一条边相连的、至少有两条边相连的、至少有三条边相连的。
第四种很好计算,直接套三元环计数板子即可,考虑剩余的如何计算。
由于笔者习惯,以下所有节点编号改为
-
所有三元组
:枚举
,分讨 在三元组中的位置: :此时 只需要满足大于 ,因此对答案贡献 ; :此时 , ,因此对答案贡献 ; :此时 只需要满足小于 ,因此对答案贡献 。
-
至少有一条边相连:
枚举所有边
,不妨设 ,考虑分讨第三个元素 与 的大小关系: :此时只需要 ,因此对答案贡献为 ; :此时只需要 ,因此对答案贡献为 ; :此时只需要 ,因此对答案贡献为 ; :此时只需要 ,因此对答案贡献为 ; :此时 ,利用等差数列求和公式得到贡献为 ; :此时 ,同理得到贡献为 ; :此时 ,贡献为 。
-
至少有两条边相连:
考虑枚举每个点的出边,先将出边按照到达节点的编号排序。设当前枚举的节点是
,到达的节点为 ,在 的所有可到达节点中排名第 , 所有可到达的节点个数为 。分讨一下 的大小关系,设第三个元素的编号为 。-
:- 若
,则 对答案贡献 ; - 若
,则 对答案贡献 。
- 若
-
:- 若
,则 对答案贡献 ; - 若
,则 对答案贡献 。
- 若
对于
对答案的贡献,也进行分讨: :此时为 ,贡献为 ; :此时 分居 两侧,贡献为 ; :此时 ,贡献为 。
-
分讨完了过后将所有情况乘上容斥系数加起来即是答案。
#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';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步