题解:P16149 [ICPC 2017 NAIPC] Maximum Color Clique
lailai0916 · · 题解
题意简述
给定一个边染色的完全图,保证每个简单环上都存在两条颜色相同的相邻边。对每个非空点集,求其中最大单色团的大小,再将所有结果相加,对
解题思路
先证明:满足条件的完全图一定存在一个节点,它向所有其他节点连出的边颜色相同。不断删除这样的节点,就能把原图化为一个有序的颜色序列。
对节点数归纳。节点数不超过
若边
若
边
- 若边
vz 的颜色为a ,环v,x,z,y,v 的颜色依次为b,a,h,a ,相邻边颜色均不相同。 - 若边
vz 的颜色为b ,环v,y,z,x,v 的颜色依次为a,h,a,b ,相邻边颜色均不相同。
两种情况都违反题目条件,所以不存在这样的
删除节点后,剩余图仍满足原条件。因此,依次找到并删除上述节点,得到顺序
现在固定一个非空点集
对于下界,取出现最多的颜色
对于上界,任意一个颜色为
然后按
若要求所选节点中每种颜色都少于
对任意非负整数
第一项中的
代码中,第一部分扫描当前剩余节点,找到单色邻接的节点后记录其颜色到 col。二维数组 f 先计算二项式系数,再按行求前缀和,保存上述 cnt 维护各颜色在已处理前缀中的数量,mx 对应 a 仅记录已经出现的颜色,未出现的颜色因子为
处理位置 col[r],保证统计范围恰好是前
寻找删除顺序需要
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=305;
const int mod=1000000007;
int c[N][N],f[N][N],col[N],cnt[N],a[N];
bool vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)cin>>c[i][j];
}
for(int i=1;i<n;i++)
{
for(int j=1;j<=n;j++)
{
if(vis[j])continue;
int val=0;
bool ok=1;
for(int k=1;k<=n;k++)
{
if(vis[k]||j==k)continue;
if(!val)val=c[j][k];
else if(val!=c[j][k]){ok=0;break;}
}
if(ok){col[i]=val;vis[j]=1;break;}
}
}
for(int i=0;i<=n;i++)
{
f[i][0]=f[i][i]=1;
for(int j=1;j<i;j++)f[i][j]=(f[i-1][j-1]+f[i-1][j])%mod;
}
for(int i=0;i<=n;i++)
{
for(int j=1;j<=i;j++)f[i][j]=(f[i][j]+f[i][j-1])%mod;
}
int ans=0,m=0,mx=0;
for(int i=1;i<=n;i++)
{
int res=(ll)(mx+1)*f[i-1][i-1]%mod;
for(int j=1;j<=mx;j++)
{
int sum=1;
for(int k=0;k<m;k++)sum=(ll)sum*f[cnt[a[k]]][min(j-1,cnt[a[k]])]%mod;
res=(res-sum+mod)%mod;
}
ans=(ans+res)%mod;
if(i<n)
{
if(!cnt[col[i]])a[m++]=col[i];
cnt[col[i]]++;
mx=max(mx,cnt[col[i]]);
}
}
cout<<ans<<'\n';
return 0;
}