白玉楼前

白玉楼前
【题目背景】
“一觉醒来怎么半灵又不见了?一定是幽幽子吃了。”
“幽幽子你给我吐出来!”
“我这边有个游戏玩不过去,你帮我玩过去我就吐出来。”
【题目描述】
妖梦现在要玩幽幽子的游戏,她才能拿回自己的半灵。
游戏规则是这样的:
幽幽子有n nn 个点,现在她让妖梦对每个点随机一条出边(随机到每个点的概率都相等),
然后得到一张图。(注意:可以自环)
如果这张图任意一个点沿着边走两步(显然这样的走法唯一)都能到达自身,则幽幽子可以通关。
现在幽幽子想问妖梦,她通关的概率是多少?
两个图不同,当且仅当存在一条边出现在图A 中且不出现在图B 中。图中的点有编号,边无编号。
答案mod 998244353
 

【数据范围】
T≤5×105,n≤5×105 T \leq 5\times 10^5,n\leq 5\times 10^5T≤5×10 
 


solution

本题求1~n的排列的对偶排列个数,即满足p[p[i]]=i的p[i]个数.

令f[i]表示前i个数的答案

f[i]=f[i-1]+(i-1)*f[i-2];

也就是它可以和自己对偶p[i]=i;

或者和任意一个人(i-1) 乘上 i-2个人的答案

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 500005
#define ll long long
#define mod 998244353
using namespace std;
int n;
ll f[maxn],ny[maxn];
ll work(ll a,int num){
    ll p=a,x=1;
    while(num){
        if(num&1)x=x*p;
        p=p*p;p%=mod;x%=mod;num>>=1;
    }
    return x;
}
int main()
{
    freopen("youmu.in","r",stdin);
    freopen("youmu.out","w",stdout);
    n=500000;
    f[0]=1;f[1]=1;
    for(int i=2;i<=n;i++){
        f[i]=f[i-1]+(ll)(i-1)*f[i-2]%mod;f[i]%=mod;
    }
    for(int i=0;i<=n;i++){
        ny[i]=work(work(i,i),mod-2);
    }
    int T;
    cin>>T;
    for(int i=1;i<=T;i++){
        scanf("%d",&n);
        ll ans=ny[n]*f[n];ans=(ans%mod+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @   liankewei123456  阅读(118)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示