CF1725C Circular Mirror

虽然是一道绿题,但是感觉推式子时的一些细节还是值得学习的,并且还是有点 2 hard 4 me......

一个圆上有 N 个可染色的点,编号 1NN 号点和 1 号点相邻。
你可以用 M 种颜色将这些点染色。要求不能出现有三个同色点围成直角三角形。
请求出全部合法方案的总数,输出它模 998 244 353 的值。

显然,作为圆直径的点对可以跟非直径的点对分成两类。如何判断直径,只需要记录一下前缀和即可,然后得到直径点对数 cnt

然后思路就有些混乱了。对于一个以直径为斜边的直角三角形,为了使它不染成同一种颜色,大体上可以归类于两种方法:

  • 把该直径上的两点染成同一种颜色,把其他所有点染成与之不同的颜色。
  • 把该直径上两点染成不同的颜色,其他点随便染。

结论看起来是简洁的,可是当时确实就绕在这两种情况里了,没能捋清楚。。。泵。

对直径上的点,染色有两种选择,自然联想到乘法原理,试着能否把两个步骤的选择数量乘起来以得其结果。但截至到目前,似乎还不太可行,因为不知道在 cnt 条直径中,哪些选择方案一染色,哪些选择方案二直接枚举
i 为选择方案一染色的直径点对数,则 cnti 为用方案二染色的直径点对数。
首先由于所有直径互不关联,故从 cnt 个直径中选 i 个直径的方案数为(cnti)m 种颜色,从里面挑 i 个出来分配到 i 条直径中,i 个直径互不影响,因此是有顺序的。挑选、分配的方案为 Ami

对于剩下的 cnti 条直径,已经选了 i 种颜色,还有 mi 种颜色。要求直径两个端点颜色不同,则其中一个端点有 mi 种颜色可选,另一个端点有 mi1 种颜色可选。因为一共有 cnti 条直径,总的方案数就是 ((mi1)×(mi))cnti

剩下还有 n2cnt 个点,每个点有 mi 种颜色选,总数就是 (mi)n2cnt
全部乘起来,求和:

ans=i=0mCcnti×Ami×((mi1)×(mi))cnti×(mi)n2×cnt

然后就完了。

#include<bits/stdc++.h> #define int long long using namespace std; const int MOD = 998244353; const int MAXN = 2e6; int fac[MAXN + 5],inv[MAXN + 5],n,m,d[MAXN + 5]; map<int,bool> vis; int qpow(int a,int n){ int ret = 1; while(n){ if(n & 1)ret = 1ll * ret * a % MOD; a = 1ll * a * a % MOD; n >>= 1; } return ret; } int c(int n,int m){ if(m > n)return 0; return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD; } int a(int n,int m){ if(n < m)return 0; return 1ll * fac[n] * inv[n - m] % MOD; } signed main(){ fac[0] = 1; for(int i = 1; i <= MAXN; i++){ fac[i] = 1ll * fac[i - 1] * i % MOD; } inv[MAXN] = qpow(fac[MAXN],MOD - 2); for(int i = MAXN; i; i--){ inv[i - 1] = 1ll * inv[i] * i % MOD; } scanf("%lld%lld",&n,&m); int sum = 0,tot = 0,cnt = 0; for(int i = 1; i <= n; i++){ scanf("%lld",&d[i]); tot += d[i]; } int p = tot; tot /= 2; vis[0] = 1; for(int i = 1; i < n; i++){ sum += d[i]; int k = sum - tot; if(vis.find(k) != vis.end())++cnt; vis[sum] = 1; } sum = 0; int x = tot - d[n]; if(p % 2 == 1){ cnt = 0; } long long ans = 0; for(int i = 0; i <= cnt; i++){ ans = (1ll * ans + 1ll * c(cnt,i) * a(m,i) % MOD * qpow(m - i,n - cnt - i) % MOD * qpow(m - i - 1,cnt - i) % MOD) % MOD; } cout << ans % MOD; }

__EOF__

本文作者Never Gonna Give You Up!
本文链接https://www.cnblogs.com/CZ-9/p/17500826.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   腾云今天首飞了吗  阅读(32)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示