[数学记录]P7752 [COCI2013-2014#2] PALETA

开始认为是并查集,但是看到不等于觉得不好传递,于是就搁下了。事后发现这是道只要去好好想,就能做的题。


题意:n 个数,ifi 颜色不同,k 色,求方案数。

把连边的图建出来。这是基环树与树组成的森林。

对于一棵树,拉一个点做根,或者说,大小为 1 的环。其它点各有 k1 种染法。总方案就是 k(k1)n1n 为树上点数。

对于基环树,把环拉出来做根。其它点都是 k1 种。而环的染法是经典小奥。

设现在考虑 n 个点,k 种颜色的环的染色。不妨认为 k 是定值,因为在实际处理中,k 一般只是参数的位置。

考虑第 n 个位置,设值为 fn

  • a1=an1。合并第 1 个位置和第 n1 个位置,贡献为 (k1)fn2

  • a1an1。情况即为 n1 时的情况,贡献为 (k2)fn1

迭代实现即可。

#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int M = 1000005, mod = 1000000007;
int qpow(int a, int b) {int ans = 1; for(; b; b >>= 1) {if(b & 1) ans = 1ll * ans * a % mod; a = 1ll * a * a % mod;} return ans;}
int n, k, ans = 1, tim, calc[M], f[M], dfn[M], cnt, ss, cnt2;
int top;
int dfs(int x){
    int xx = x;
    for(; ;){
        // if(f[x] == x) return 1;
        if(dfn[x]) return dfn[x] >= dfn[top] ? cnt - dfn[x] + 1 : 0;
        dfn[x] = ++cnt; x = f[x]; 
    }
}
void work(int x){
    top = x; int siz = dfs(x);
    if(siz > 0){
        ans = 1ll * ans * calc[siz] % mod; ss += siz;
    } 
}
int main(){
    scanf("%d %d", &n, &k);
    calc[0] = 1; calc[1] = k; calc[2] = 1ll * k * (k-1) % mod; calc[3] = 1ll * k * (k-1) * (k-2) % mod;
    for(int i = 4; i <= n; i++){
        calc[i] = (1ll * (k-1) * calc[i-2] % mod + 1ll * (k-2) * calc[i-1] % mod) % mod;  
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d", &f[i]);
    }
    for(int i = 1; i <= n; i++) if(!dfn[i]) work(i);
    // printf("%d %d\n", ans, ss);
    printf("%d\n", 1ll * ans * qpow(k-1, n-ss) % mod);
}

作者:purplevine

出处:https://www.cnblogs.com/purplevine/p/16589620.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   purplevine  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示