首页 > 其他分享 >P7438 更简单的排列计数 题解

P7438 更简单的排列计数 题解

时间:2023-08-12 09:55:49浏览次数:38  
标签:ix limits int 题解 sum P7438 计数 dfrac mod

前置芝士:伯努利数等幂求和。其中伯努利数 \(B_i\) 的生成函数为 \(\frac{x}{e^x-1}\)。


首先这种逆序对有个套路的 dp:令 \(f_{i,j}\) 表示填了前 \(i\) 个数,逆序对为 \(j\),这时排列的 \(val_{\pi}\) 的乘积之和。

有转移:\(f_{i,j}=\sum\limits_{k=0}^{i-1} f_{i-1,j-k}i^k\),初始 \(f_{0,0}=1\)。

看到出题人为卡老师想到多项式。令 \(f_n(x)=\sum\limits_{i=0}^m f_{n,i}x^i\),则转移变成:\(f_n(x)=\sum\limits_{k=0}^{n-1} f_{n-1}(x)x^kn^k=\dfrac{f_{n-1}(x)(1-(nx)^n)}{1-nx}\)。

于是 \(f_n(x)=\prod\limits_{i=1}^n \dfrac{1-(ix)^i}{1-ix}\),要求其 \(0\sim m\) 次项。

上面:

\(\prod\limits_{i=1}^n (1-(ix)^i)=\exp(\sum\limits_{i=1}^n \ln(1-(ix)^i))=\exp\left(-\sum\limits_{i=1}^n\sum\limits_{j=1}^m\dfrac{(ix)^{ij}}{j}\right)\)。

由于只需求其 \(0\sim m\) 次项,于是枚举 \(i,j\) 的复杂度为 \(O(m\log m)\)。总复杂度 \(O(m\log m)\),因为实现精细能规避快速幂。注意 \(i\) 的枚举范围时 \(1\sim \min(n,m)\)。

下面:

\(\prod\limits_{i=1}^n (1-ix)^{-1}=\exp(-\sum\limits_{i=1}^n \ln(1-ix))=\exp\left(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\dfrac{(ix)^j}{j}\right)\) 。

考虑令 \(\exp\) 里面的式子为 \(f(x)\),则 \(f(x)=\sum\limits_{j=1}^m \dfrac{x^j}{j}\sum\limits_{i=1}^n i^j\)。

注意到里面为等幂求和,有:\(\sum\limits_{i=1}^n i^j=\frac{1}{j+1}\sum\limits_{i=0}^j\binom{j+1}{i}B_i(n+1)^{j+1-i}\)。

于是 \(f(x)=\sum\limits_{j=1}^m \dfrac{x^j}{j(j+1)}\sum\limits_{i=0}^j(j+1)!\times \dfrac{B_i (n+1)^{j+1-i}}{i!(j+1-i)!}=\sum\limits_{j=1}^m x^j(j-1)!\sum\limits_{i=0}^j\dfrac{B_i}{i!}\times \dfrac{(n+1)^{j+1-i}}{(j+1-i)!}\)。

令 \(a_i=\dfrac{B_i}{i!},b_i=\dfrac{(n+1)^{i+1}}{(i+1)!}\),则把 \(a,b\) 卷积就是后半部分,最后第 \(j\) 项系数乘个 \((j-1)!\) 即可。


注意到我们已经把分母 \(-1\) 次方了,于是最后求出的分子分母两个多项式做一个卷积即可,复杂度 \(O(m\log m)\),常数较大。

代码:

#include<bits/stdc++.h>
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define LL long long
using namespace std;
const int mod=998244353,N=4e6+5;
int n,m,Bo[N],a[N],b[N],c[N],w[N],jc[N],inv[N],I[N],mmax;
inline int rd()
{
    int x=0,zf=1;char ch=getchar();
    while(ch<'0'||ch>'9') (ch=='-')and(zf=-1),ch=getchar();
    while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1)+ch-'0')%mod,ch=getchar();
    return x*zf;
}
inline void wr(int x)
{
    if(x==0) return putchar('0'),putchar(' '),void();
    int num[35],len=0;
    while(x) num[++len]=x%10,x/=10;
    for(int i=len;i>=1;i--) putchar(num[i]+'0');
    putchar(' ');
}
inline int bger(int x){return x|=x>>1,x|=x>>2,x|=x>>4,x|=x>>8,x|=x>>16,x+1;}
inline int md(int x){return x>=mod?x-mod:x;}
inline int yy(int x){if(x&1) return (x+mod)>>1;return x>>1;}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
inline void dao(int *a,int n){for(int i=1;i<n;i++) a[i-1]=1ll*i*a[i]%mod;a[n-1]=0;}
inline void ji(int *a,int n){for(int i=n-1;i>=1;i--) a[i]=1ll*ksm(i,mod-2)*a[i-1]%mod;a[0]=0;}
inline void init(int mmax)
{
	for(int i=1,j,k;i<mmax;i<<=1)
		for(w[j=i]=1,k=ksm(3,(mod-1)/(i<<1)),j++;j<(i<<1);j++)
			w[j]=1ll*w[j-1]*k%mod;
}
inline void DNT(int *a,int mmax)
{
	for(int i,j,k=mmax>>1,L,*W,*x,*y,z;k;k>>=1)
		for(L=k<<1,i=0;i<mmax;i+=L)
			for(j=0,W=w+k,x=a+i,y=x+k;j<k;j++,W++,x++,y++)
				*y=1ll*(*x+mod-(z=*y))* *W%mod,*x=md(*x+z);
}
inline void IDNT(int *a,int mmax)
{
	for(int i,j,k=1,L,*W,*x,*y,z;k<mmax;k<<=1)
		for(L=k<<1,i=0;i<mmax;i+=L)
			for(j=0,W=w+k,x=a+i,y=x+k;j<k;j++,W++,x++,y++)
				z=1ll* *W* *y%mod,*y=md(*x+mod-z),*x=md(*x+z);
	reverse(a+1,a+mmax);
	for(int inv=ksm(mmax,mod-2),i=0;i<mmax;i++) a[i]=1ll*a[i]*inv%mod;
}
inline void NTT(int *a,int *b,int n,int m)
{
	mmax=bger(n+m);init(mmax);
	DNT(a,mmax);DNT(b,mmax);
	for(int i=0;i<mmax;i++) a[i]=1ll*a[i]*b[i]%mod;
	IDNT(a,mmax);
}
void INV(int num,int *a,int *b)
{
	if(num==1) return b[0]=ksm(a[0],mod-2),void();INV((num+1)>>1,a,b);
	int mmax=bger(num<<1);init(mmax);static int c[N];
	for(int i=0;i<num;i++) c[i]=a[i];for(int i=num;i<mmax;i++) c[i]=0;DNT(c,mmax);DNT(b,mmax);
	for(int i=0;i<mmax;i++) b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;IDNT(b,mmax);
	for(int i=num;i<mmax;i++) b[i]=0;
}
inline void Ln(int *a,int n){static int b[N];for(int i=0;i<bger(n<<1);i++) b[i]=0;INV(n,a,b);dao(a,n);NTT(a,b,n,n);ji(a,n);for(int i=n;i<bger(n<<1);i++) a[i]=0;}
inline void Exp(int *a,int *b,int n)
{
	if(n==1) return b[0]=1,void();
	Exp(a,b,(n+1)>>1);static int c[N];for(int i=0;i<bger(n<<1);i++) c[i]=0;
	for(int i=0;i<n;i++) c[i]=b[i];Ln(c,n);
	for(int i=0;i<n;i++) c[i]=md(mod-c[i]+a[i]);c[0]=md(c[0]+1);
	NTT(b,c,n,n);for(int i=n;i<bger(n<<1);i++) b[i]=0;
}
int main()
{
	n=rd();m=rd()+1;for(int i=jc[0]=1;i<=m;i++) jc[i]=1ll*jc[i-1]*i%mod;
	inv[m]=ksm(jc[m],mod-2);for(int i=m-1;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	for(int i=0;i<m;i++) a[i]=inv[i+1],I[i]=ksm(i,mod-2);INV(m,a,Bo);
	for(int i=0;i<m;i++) a[i]=Bo[i],b[i]=1ll*ksm(n+1,i+1)*inv[i+1]%mod;
	NTT(a,b,m-1,m-1);for(int i=m;i<mmax;i++) a[i]=b[i]=0;
    a[0]=b[0]=0;for(int i=1;i<m;i++) a[i]=1ll*a[i]*jc[i-1]%mod,b[i]=0;
	Exp(a,b,m);for(int i=0;i<mmax;i++) a[i]=0;
	for(int i=1;i<min(m,n+1);i++) for(int j=1,w=ksm(i,i),s=w;j*i<m;j++,s=1ll*s*w%mod) a[i*j]=(a[i*j]+1ll*s*I[j])%mod;
	for(int i=1;i<m;i++) a[i]=mod-a[i];Exp(a,c,m);NTT(b,c,m-1,m-1);
	for(int i=0;i<m;i++) wr(b[i]);
	return 0;
}

标签:ix,limits,int,题解,sum,P7438,计数,dfrac,mod
From: https://www.cnblogs.com/HaHeHyt/p/17624380.html

相关文章

  • 8.11 格路计数与乐子题
    邮戳拉力赛好题啊!写了一个错误的解,但仍未知道错在哪里。容易发现路径一定是:向上走,到一个点后向下走,走到一个点后再向上走,以此类推。往下走时,可以自由选择是下行时盖章还是上行时盖章,这也是一直往上走不最优的理由。从\(0\)向上走到\(n+1\)的路径长度可以最后再加,不用考虑......
  • P7092 计数题 题解
    前置题目:P5748集合划分计数。我们令\(Bell_n\)表示将\(n\)个有标号的球划分为若干集合的方案数。且\(Bell_n=n![x^n]e^{e^x-1}\)。首先,当\(k=0\)时,\(\mu(S)=0\),答案为\(0\)。当\(k=1\)时,\(\mu(S)=(-1)^{|S|},\varphi(S)=\prod\limits_{x\inS}(x-1)\)。记\(\pi(S)......
  • [ABC309G] - Ban Permutation 题解
    [ABC309G]-BanPermutation题解题目描述求长为\(N(N\leq100)\)且满足以下条件的排列\(P=(P_1,P_2,...,P_N)\)的个数,模\(998244353\):\(\forall1\leqi\leqN\),\(|P_i-i|\geqX(X\leq5)\)。思路首先拆绝对值,得到:\[P_i\geX+i\veeP_i\leX-i\]数数题除了排列......
  • 洛谷-P9496 题解
    正文在讲解之前,先来几种简单情况:让\(n=1\)转变成\(m=0\),只需要让\(n\land0\)即可;让\(n=0\)转变成\(m=1\),只需要让\(n\lor1\)即可。将\(n\)扩展成更大的。对于\(n\)二进制的每一位数,只需要按上述情况处理即可,而由于可以对任意数进行位运算,所以相同类型的位运......
  • 【题解】Educational Codeforces Round 147(CF1821)
    自己做出来了A-E,F算是搞懂GF后第一道符合我这个菜鸡水平的实战,可惜的是根本没意识到可以GF。A.Matching题目描述:整数模板是每位均为数字或问号的字符串。如果可以用数字替换模板中的每个问号,从而获得该正整数(严格大于\(0\))的十进制表示形式,且不带任何前导零,则该正整数......
  • Codeforces Round 874 (Div. 3) 题解
    A.MusicalPuzzle字符串\(s\)的不同的长度为\(2\)的子串个数就是答案可以用set处理B.RestoretheWeather将\(a\)数组排序后,在\(b\)数组中找到第一个大于等于\(a_i-k\)的元素与\(a_i\)对应即可可以用multiset实现(用multiset自带的lower_bound()比较好,......
  • Codeforces Round 878 (Div. 3) 题解
    A.CipherShifer从头开始扫一遍即可,扫到两个相同的表示某一个字符的解密结束B.BinaryCafe首先,我们不妨把题意转换为有多少种不同的花钱方案因为每一种咖啡就是一个二进制有\(k\)位的数字的其中一位,而对于不同的方案,其二进制位不完全相同,则每一个方案对应的花费一定不同,......
  • ARC137D Prefix XORs 题解
    这里的所有下标从\(\bm0\)开始。我们考察一下每次操作后的数列\(a\)会是什么样的。这里用\(a_i\)前面的系数\(x\)表示\(a_i\)贡献了\(x\)次,\(+\)表示异或。\[\begin{matrix}k=0&a_0&a_1&a_2&\cdots&a_{n-1}\\k=1&a_0&a_0+a_1&a_0+a_1+a_2&\cdots&......
  • Subtree 题解
    Subtree题目大意给定一颗树,你可以选出一些节点,你需要对于每个点求出在强制选这个点的情况下所有选择的点联通的方案数,对给定模数取模。思路分析对于这种求树上每一个点方案数的题目,首先考虑换根DP。强制嵌定树根为\(1\),设\(f_i\)表示在\(i\)的子树中选点,\(i\)强制选,所......
  • 国标GB28181视频云服务平台LntonGBS(源码)国标平台对接宇视SDK,多次点击录像回放出现崩溃
    LntonGBS是一款基于国标GB28181协议的视频云服务平台。通过该平台,可以实现设备接入并支持视频的实时监控直播、录像、语音对讲、云存储、告警、级联等功能。此外,LntonGBS还支持将接入的视频流进行全终端、全平台的分发,包括支持RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流分发。另......