题目大意:有n个点,(n是6的倍数)相邻的每三个点构成一个三角形,依次给出每条边的权值,要求用红色和暗色给每一个点涂色,且要求两种颜色的点各占总点数的一半,现定义整幅图的权值等于连接两个不同颜色点的边的权值和,求有多少种使整幅图权值最大的涂色方式
6<=n<=3e5;1<=wi<1000
思路:因为要求一半蓝一半红,所以最基础的单位是两个三角形,对于两个三角形,总体有两大种涂色方案:一个三角形全红,另一个全蓝;或者两个三角形1红+2蓝和1蓝+2红,因为只有连接颜色不同的点的边才会被记录,所以显然后者权值才能最大,那么对于每个三角形,都可以将两条边的权值计入整幅图的权值中,要想选最大,也就是每个三角形要选出两个权值最大的边,我们暂时先不考虑这个三角形是1蓝2红还是1红2蓝的问题,如果这个三角形的三条边是形如4,2,2这样两条小边相等的情况,那我们可以选择1,2两条边或1,3两条边有两种情况,如果这个三角形是形如2,2,2这样三条边都相等的情况,那么我们可以选择1,2;2,3或1,3三种情况,对于其余的三角形都只有1种情况,然后我们再考虑n/3个三角形中要选出n/6个1蓝2红,其余都是1红2蓝,也就是要再*C(n/6,n/3)即可
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
const int MOD = 998244353;
using namespace std;
int a[5];
ll fac[N];
ll qpow(ll a, ll b)
{//快速幂,用于求逆元
ll ret = 1;
while (b > 0)
{
if (b & 1)
{
ret = ret * a % MOD;
}
b >>= 1;
a = a * a % MOD;
}
return ret;
}
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
int n;
cin >> n;
ll ans = 1;
n /= 3;//将n变成三角形的数量
fac[0] = 1;
for (int i = 1; i <= n; i++)
{
fac[i] = fac[i - 1] * i % MOD;//预处理阶乘数组
for (int j = 1; j <= 3; j++)
{
cin >> a[j];
}
sort(a + 1, a + 4);//将三角形的三条边按从小到大排序
if (a[1] == a[2] && a[1] == a[3])
{//三个数都相等,答案*3
ans = ans * 3 % MOD;
}
else if (a[1] == a[2])
{//两个小数相等,答案*2
ans = ans * 2 % MOD;
}
}
ans = ans * fac[n] % MOD * qpow(fac[n / 2] * fac[n - n / 2] % MOD, MOD - 2) % MOD;
//C(n/2,n)=n!/(n/2)!/(n-n/2)!
cout << ans << endl;
return 0;
}