D. Triangle Coloring

文章讨论了一个图论问题,给定多个边权不同的三角形,需要进行染色使得蓝色和红色点数量相等,同时最大化不同颜色边的权值之和。通过分析三角形边权的三种情况,结合乘法原理和组合数计算所有可能的方案,并应用卢卡斯定理处理大数模运算避免溢出。最后提供了一段C++代码实现解决方案。
摘要由CSDN通过智能技术生成

D. Triangle Coloring

1、题目

D. Triangle Coloring

大意就是给我们多个三元组,每个三元组构成一个三角形,三元组内的三个值分别代表三条边的边权。就这样,多个三角形构成了整个图。我们需要给每个三角形内的任意两个点染色,颜色分为两种:蓝色和红色。然后连接两个不同颜色的边将被记录下来。染色的过程中,对于整个图而言,我们需要保证蓝色点的数目和红色点的数目是相同的。

同时,我们还需要保证我们所被记录的边权之和是所有情况中的最大值。在这两个条件的限制下,我们需要求出所有的方案数。

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();
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值