【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;
}

浙公网安备 33010602011771号