【2020-2021集训队作业】Yet Another Permutation Problem

【2020-2021集训队作业】Yet Another Permutation Problem

Description

有一个长为\(n\)的序列,第\(i\)个数为\(i\)

每次操作可以选择一个数,将其放至开头或结尾

对于每个\(k\in[0,n-1]\),求出至多进行\(k\)次操作能得到的排列数,对\(m\)取模

Input

一行两个数\(n,m\)

Output

输出\(n\)行表示答案

Sample Input

3 998244353

Sample Output

1
5
6

Data Constraint

\(1\le n\le 1000\)

Solution

符号化容斥tql

对于一个\(k\)

实际上要算的就是存在一个上升段的长度\(l\),使得\(k\ge n-l\)的排列数

可以容斥转化成数所有段长度\(l<n-k\)的方案数

对于一个\([l<k]\)(和上面的不一样)

用GF容斥,设为\(G(x)\),对于一个单位,我们希望\([x^i]\)\([i<k]\)

\(\frac{1}{1-G(x)}=\sum_{i=0}^{k-1}x^i=\frac{1-x^{k}}{1-x}\\\)

解得\(G(x)=\frac{x-x^{k}}{1-x^k}\\\)

然后写出\(EGF\),即\(F(x)=\sum_{i=0}^{+\infty}(\frac{x^{ik+1}}{(ik+1)!}-\frac{x^{k(i+1)}}{(ik+k)!})\\\)

现在要求的就是\(\frac{1}{1-F(x)}\)

可以移项,然后递推,可以发现\(F\)中的项数只有\(O(\frac{n}{k})\)

于是总复杂度就是\(O(n^2\ln n)\)

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 1010

int fac[N],ifac[N],n,mo,f[N],g[N];

int mod(int x){return x>=mo?x-mo:x;}

int mi(int x,int y){
	if(y==1)return x;
	return y&1?1ll*x*mi(1ll*x*x%mo,y/2)%mo:mi(1ll*x*x%mo,y/2);
}

int main(){
	scanf("%d%d",&n,&mo);
	fac[0]=1;
	F(i,1,N-10)fac[i]=1ll*fac[i-1]*i%mo;
	ifac[N-10]=mi(fac[N-10],mo-2);
	Fd(i,N-11,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mo;
	F(i,0,n-1){
		int A=n-i;
		memset(g,0,sizeof(g));
		g[0]=1;
		F(j,1,n){
			int tmp=0;
			F(k,0,j/A+1){
				if(k*A+1<=j)tmp=mod(tmp+1ll*ifac[k*A+1]*g[j-k*A-1]%mo);
				if(k*A+A<=j)tmp=mod(tmp-1ll*ifac[k*A+A]*g[j-k*A-A]%mo+mo);
			}
			g[j]=tmp;
		}
		printf("%d\n",mod(fac[n]-1ll*fac[n]*g[n]%mo+mo));
	}
	return 0;
}
posted @ 2022-11-01 16:08  冰雾  阅读(31)  评论(0编辑  收藏  举报