D. Triangle Coloring
1、题目
大意就是给我们多个三元组,每个三元组构成一个三角形,三元组内的三个值分别代表三条边的边权。就这样,多个三角形构成了整个图。我们需要给每个三角形内的任意两个点染色,颜色分为两种:蓝色和红色。然后连接两个不同颜色的边将被记录下来。染色的过程中,对于整个图而言,我们需要保证蓝色点的数目和红色点的数目是相同的。
同时,我们还需要保证我们所被记录的边权之和是所有情况中的最大值。在这两个条件的限制下,我们需要求出所有的方案数。
2、分析
对于一个三角形而言,分为下面三种情况:
情况1
三条边的边权是一样的, 那么我们随便选,那么一共就有三种可能。
情况2
三条边中有两条边是一样的。此时还需要再细分为两种情况,如果这两条边是大于第三边的,那么我们只能选择这两个相同的边,此时只有一种选择的可能。如果第三条边是最大值的话,我们就可以在这两个相同的边之间任意选择一条边。此时就有两种可能。
情况3
如果三条边是不同的,那么我们就只有一种可能,即选择最大的两条。
根据乘法原理,我们就需要去遍历每一个三元组然后分析可能的情况,最后乘在一起。同时,我们还需要注意的是,我们需要让整个图两个颜色的点是相同的。 即我们需要在 m m m个三元组内,任意挑选 m / 2 m/2 m/2个,那么我们选择的一半三元组里是两个蓝一红,剩余的是两红一蓝。这是一个组合数的过程。
最后将组合数和刚才的可能数乘在一起。
这个过程中,组合数可能爆掉,所以对一个非质数进行了取模操作,所以套一个卢卡斯定理的模板即可。
3、代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int N = 3e5 + 10;
ll qmi(ll a,ll b,ll p)
{
ll res = 1;
while(b)
{
if(b & 1)res = res % p * a % p;
a = a % p * a % p;
b >>= 1;
}
return res;
}
ll c(ll a,ll b, ll p)
{
if(b > a)return 0;
ll res = 1;
for(int i = 1,j = a;i <= b; i++,j--)
{
res = res % p * j % p;
res = res % p * qmi(i, p-2, p) % p;
}
return res;
}
ll lucas(ll a,ll b,ll p)
{
if(a < p && b < p)return c(a,b,p);
else return c( a % p,b % p, p) * lucas(a / p, b / p, p ) % p;
}
void solve()
{
int n;
cin >> n;
vector<int>v(n);
int cnt = 0;
ll res = 1;
for(int i = 0; i < n; i ++ )
{
cin >> v[i];
cnt ++;
if(cnt == 3)
{
cnt = 0;
int a = v[i], b = v[i - 1], c = v[i - 2];
int maxv = 0;
maxv = max(a, max(b, c));
if(a != b && b != c && c != a)
res *= 1;
else if( a == b && b == c && a == c)
res = (res * 3) % mod;
else
{
multiset<int> ma;
ma.insert(a);
ma.insert(b);
ma.insert(c);
if(ma.count(maxv) != 2)
res = (res * 2) % mod;
else
res *= 1;
}
}
}
//cout << res << endl;
cout << ( res * lucas(n / 3, n / 6, mod) ) % mod << endl;
}
bool judge(int x)
{
for(int i = 2; i < x; i ++ )
{
if(x % i)
return false;
}
return true;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}