题目大意:
对每个
求有多少长为
的本质不同的排列,其中两个排列
本质相同,当且仅当
,其中:
,对
取模,
为质数。
题解:
考虑给你一个排列
。
称一个区间是强连续的当且仅当区间中值与下标的和全相等,或者差全相等。
那么我们将所有极长的强连续区间缩起来,这样就变成一个子问题。
但是有可能一个区间不存在长度大于等于2的强连续区间,但是发现一个排列不存在长度大于等于2的强连续区间当且仅当其长度大于等于4,并且只存在一种本质不同的这样的排列。
因此将上述过程描述成一颗树,一个点要么为叶子,要么是强连续区间,要么是直接全缩起来的。第二种情况要至少两个儿子,第三种情况要至少四个儿子。
因此设
为确定叶子数量答案的生成函数,那么显然:
牛顿迭代上式即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace OUTPUT_SPACE{
char ss[2000000],tt[30];int ssl,ttl;
inline int print(int x)
{
if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
}
inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int p,yg,pri[100];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
inline int get_yg()
{
int c=0,x=p-1;
rep(i,2,x/i) if(x%i==0) for(pri[++c]=i,x/=i;x%i==0;x/=i);
for(yg=2;;yg++)
{
int ok=1;
rep(i,1,c) if(fast_pow(yg,(p-1)/pri[i])==1) { ok=0;break; }
if(ok) return 0;
}
return 0;
}
namespace NTT_space{
const int N=1000010;int A[N],B[N],r[N];
inline int show(int *a,int n) { rep(i,0,n-1) cerr<<a[i]sp;cerr ln;return 0; }
inline void clr(int *a,int n) { memset(a,0,sizeof(int)*n); }
inline void cpy(int *a,int *b,int n) { memcpy(a,b,sizeof(int)*n); }
inline int NTT(int *a,int n,int s)
{
int t=1,L=0;while(t<n) t<<=1,L++;
rep(i,1,n-1) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
rep(i,1,n-1) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2;i<=n;i<<=1)
{
int wn=fast_pow(yg,s>0?(p-1)/i:p-1-(p-1)/i);
for(int j=0,t=i>>1,x,y;j<n;j+=i)
for(int k=0,w=1;k<t;k++,w=(lint)w*wn%p)
x=a[j+k],y=(lint)w*a[j+k+t]%p,a[j+k]=x+y,a[j+k+t]=x-y,
(a[j+k]>=p?a[j+k]-=p:0),(a[j+k+t]<0?a[j+k+t]+=p:0);
}
if(s<0) for(int i=0,ninv=fast_pow(n,p-2);i<n;i++) a[i]=(lint)a[i]*ninv%p;
return 0;
}
inline int tms(int *a,int m1,int *b,int m2,int *c,int m3=-1)
{
int n=1;while(n<m1+m2-1) n<<=1;
clr(A,n),cpy(A,a,m1),NTT(A,n,1);
clr(B,n),cpy(B,b,m2),NTT(B,n,1);
rep(i,0,n-1) A[i]=(lint)A[i]*B[i]%p;
return NTT(A,n,-1),cpy(c,A,m3<0?m1+m2-1:m3),0;
}
namespace POLYINV_space{
int b[N],h[N];
inline int polyinv(int *a,int m,int *res)
{
int n=1;while(n<m) n<<=1;
clr(b,n),b[0]=fast_pow(a[0],p-2);
for(int i=2;i<=m;i<<=1)
{
cpy(h,b,i);rep(j,0,(i>>1)-1) h[j]+=h[j],(h[j]>=p?h[j]-=p:0);
tms(b,i>>1,b,i>>1,b,i),tms(b,i,a,i,b,i);
rep(j,0,i-1) b[j]=h[j]-b[j],(b[j]<0?b[j]+=p:0);
}
return cpy(res,b,m),0;
}
}using POLYINV_space::polyinv;
int fs[N];
namespace SOLVE_space{
int f[N],a[N],b[N];
inline int solve(int m,int *ans)
{
int n=1;while(n<=m) n<<=1;
clr(f,n),f[0]=0;
for(int i=2;i<=n;i<<=1)
{
int t=i<<1,w=1,wn=fast_pow(yg,(p-1)/t),f1,f2,f3,f4;
cpy(fs,f,i>>1),NTT(f,t,1);
rep(j,0,t-1)
f1=f[j],f2=(lint)f1*f1%p,f3=(lint)f2*f1%p,f4=(lint)f2*f2%p,
a[j]=(f4+2ll*f2-(w+1ll)*f1+w)%p,(a[j]<0?a[j]+=p:0),
b[j]=(4ll*f3+4ll*f1-w-1)%p,(b[j]<0?b[j]+=p:0),w=(lint)w*wn%p;
NTT(b,t,-1),polyinv(b,i,b),NTT(a,t,-1),tms(a,i,b,i,a,i);
cpy(f,fs,i>>1),clr(f+(i>>1),t-(i>>1));
rep(j,0,i-1) f[j]-=a[j],(f[j]<0?f[j]+=p:0);
}
return cpy(ans,f,m+1),0;
}
}using SOLVE_space::solve;
}
const int N=100010;
int ans[N];
int main()
{
int n=inn();p=inn(),get_yg();
NTT_space::solve(n,ans);
rep(i,1,n) print(ans[i]);
return Flush(),0;
}