cf1697 E. Coloring

题意:

n 种颜色给 n 个点染色,每种颜色可重复使用,不必用上所有颜色。距离为曼哈顿距离,要求:

  • 若有三点同色则任两点间的距离相等
  • 若点 a,b 同色而点 c 不同色,则 dis(a,b)<dis(a,c),dis(b,c)

问染色方案数取模

n100

思路:

考虑把所有点划分成若干集合,每个集合中的所有点要么同色,要么全都不同色。不属于同一集合的两点必不同色。所在集合的大小为1的点称为孤立点

mind(i) 表示 i 到其他点的最短距离

如果 dis(i,j)=mind(i)=mind(j),那么 i,j 要么属于同一集合,要么都是孤立点。这一性质是 “双向” 的,我们先用它来构造初始集合

如果 dis(i,j)=mind(i),那么 i 要么是孤立的,要么在 j 的集合中;否则 ij 不可能在同一集合。我们用这一性质来拆散不合法的集合

然后把所有集合的大小拿出来做dp。f(i,j) 表示处理到第 i 个集合,要用 j 种颜色。那么 f(i,j)=f(i1,j1)+f(i1,j|Si|)

答案是 Anif(m,i)m 为集合总数,要乘一个排列数给它们上色。

用并查集维护集合。代码看起来繁琐,但其实构造集合的思路极其简单,后面的dp也是入门级别

void chai(int x) { //把并查集中的每个点拆成独立
    for(int i = 1; i <= n; i++)
        if(get(i) == x) p[i] = i;
}

void sol() {
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> x[i] >> y[i];

    for(int i = 1; i <= n; i++) { //距离矩阵
        mind[i] = INF; //离i最近的点的距离
        for(int j = 1; j <= n; j++) if(i != j)
            d[i][j] = abs(x[i]-x[j]) + abs(y[i]-y[j]),
            mind[i] = min(mind[i], d[i][j]);
    }
    for(int i = 1; i <= n; i++) //构造集合
        for(int j = i+1; j <= n; j++)
            if(d[i][j] == mind[i] && d[i][j] == mind[j])
                merge(i, j);
    for(int i = 1; i <= n; i++) //拆散不合法的集合
        for(int j = 1; j <= n; j++) if(i != j)
            if(d[i][j] == mind[i] && get(i) != get(j) ||
            d[i][j] != mind[i] && get(i) == get(j)) chai(get(i));

    for(int i = 1; i <= n; i++) cnt[get(i)]++; //最终的集合
    for(int i = 1; i <= n; i++)
        if(cnt[i]) cnt[++m] = cnt[i]; //去掉零
    
    f[0][0] = 1; for(int i = 1; i <= m; i++) //dp
        for(int j = 1; j <= n; j++) {
            (f[i][j] += f[i-1][j-1]) %= mod;
            if(cnt[i] > 1 && j >= cnt[i])
                (f[i][j] += f[i-1][j-cnt[i]]) %= mod;
        }
    ll ans = 0; for(int i = 1; i <= n; i++) //统计答案
        (ans += A(n, i) * f[m][i] % mod) %= mod;
    cout << ans;
}
posted @   Bellala  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示