Cards(ABC 247 F)
题目大意
你有张卡片,每张卡有正反两面,正面有一个数字,反面有一个数字,数列和都是的全排列,问有多少种选择方法使得个数都至少一次出现在被选中的牌上,答案对取模。
思路
首先,我们建一张图,把每张牌正反的两个数连起来,而由于和是全排列,每个数都只会出现两次,每个点的度都是,所以我们建出来的图会由很多个环构成。然后我们先来考虑一个简单一点的问题:这个数中相邻的两个数至少得选一个的方案数是多少。就是分类讨论是否选,这样的话,设答案为,则满足。然后现在我们要求的是这个数围成一个圈时连着一个点的两条边至少得选一条的方案数,设答案为,分类讨论一下和是否相连,就能得到,观察一下可以发现,为卢卡斯数列。这样,我们只要把每个环的答案乘起来就结束了。
代码
#include<bits/stdc++.h> using namespace std; long long a[200005]; long long mod=998244353; int p[200005]; int q[200005]; int fa[200005]; int siz[200005]; int vis[200005]; int findd(int x) { return fa[x]==x?x:(fa[x]=findd(fa[x])); } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&p[i]); for(int i=1;i<=n;i++)scanf("%d",&q[i]); for(int i=1;i<=n;i++){fa[i]=i;siz[i]=1;} for(int i=1;i<=n;i++)if(findd(p[i])!=findd(q[i])) { siz[findd(q[i])]+=siz[findd(p[i])]; fa[findd(p[i])]=findd(q[i]); } a[0]=2; a[1]=1; for(int i=2;i<=n;i++)a[i]=(a[i-1]+a[i-2])%mod; long long ans=1; for(int i=1;i<=n;i++)if(!vis[findd(i)]) { ans=ans*a[siz[findd(i)]]%mod; vis[findd(i)]=1; } printf("%lld\n",ans); return 0; }
__EOF__

本文作者:Jerry-Black
本文链接:https://www.cnblogs.com/Jerry-Black/p/16208282.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
本文链接:https://www.cnblogs.com/Jerry-Black/p/16208282.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)