[数学记录]P7752 [COCI2013-2014#2] PALETA
开始认为是并查集,但是看到不等于觉得不好传递,于是就搁下了。事后发现这是道只要去好好想,就能做的题。
题意: 个数, 与 颜色不同, 色,求方案数。
把连边的图建出来。这是基环树与树组成的森林。
对于一棵树,拉一个点做根,或者说,大小为 的环。其它点各有 种染法。总方案就是 , 为树上点数。
对于基环树,把环拉出来做根。其它点都是 种。而环的染法是经典小奥。
设现在考虑 个点, 种颜色的环的染色。不妨认为 是定值,因为在实际处理中, 一般只是参数的位置。
考虑第 个位置,设值为 :
-
。合并第 个位置和第 个位置,贡献为
-
。情况即为 时的情况,贡献为
迭代实现即可。
#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 国际」许可协议进行许可。
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/16589620.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现