[洛谷]-5825排列计数-欧拉数、NTT
https://www.luogu.com.cn/problem/P5825
题意:我们记一个排列 P 的升高为
给定排列长度
题解:就是要我们求欧拉数(Eulerian Number)
边界
先看看边界:
对称性
同样不难发现类似组合数那样的对称性:
递推形式
考虑递推形式的时候经常可以考虑增加一个元素产生的影响,假设想求
考虑
用递推形式看起来是可以
在这个题里就要求我们算一行(一列似乎没什么太好的做法?——)
容斥
这一部分来自于EI的一篇博客: https://www.luogu.com.cn/blog/EntropyIncreaser/solution-p5825 ,这里大概相当于做一个更详细的注解。
欲求
问题转化成:有
更进一步只要考虑
因此只要考虑:
因此最终答案是:
非常标准的卷积形式,一次卷积即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; const int MOD=998244353; const int N=1<<20; int ksm(int a,int b){ int ret=1;a%=MOD; for(;b;b>>=1,a=(ll)a*a%MOD)if(b&1)ret=(ll)ret*a%MOD; return ret; } int n,fact[N],inv_fact[N],f[N],g[N],r[N],w[N]; void ntt(int n,int *x,int op){ rep(i,0,n-1)if(r[i]<i)swap(x[i],x[r[i]]); for(int i=1;i<n;i<<=1){ int gn=ksm(op==1?3:332748118,(MOD-1)/(i<<1)); w[0]=1; for(int k=1;k<i;k++)w[k]=(ll)w[k-1]*gn%MOD; for(int j=0;j<n;j+=(i<<1)) for(int k=0;k<i;k++){ int t1=x[j+k],t2=(ll)x[j+k+i]*w[k]%MOD; x[j+k]=(t1+t2)%MOD; x[j+k+i]=(t1-t2+MOD)%MOD; } } if(op==-1){ int inv=ksm(n,MOD-2); rep(i,0,n-1)x[i]=(ll)x[i]*inv%MOD; } } int main(){ fastio; cin>>n; fact[0]=1; rep(i,1,N-5)fact[i]=(ll)fact[i-1]*i%MOD; inv_fact[N-5]=ksm(fact[N-5],MOD-2); for(int i=N-5;i>=1;i--)inv_fact[i-1]=(ll)inv_fact[i]*i%MOD; rep(i,0,n){ f[i]=(ll)fact[n+1]*inv_fact[i]%MOD*inv_fact[n+1-i]%MOD; if(i&1)f[i]=(MOD-f[i])%MOD; g[i]=ksm(i,n); } int p=1,deg=n+n; while(p<=deg)p<<=1; for(int i=0;i<p;i++)r[i]=(i&1)*(p>>1)+(r[i>>1]>>1); ntt(p,f,1);ntt(p,g,1); rep(i,0,p-1)f[i]=(ll)f[i]*g[i]%MOD; ntt(p,f,-1); rep(i,0,n)cout<<f[n-i]<<' '; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现