模数m不是质数很麻烦qwq
先把他分解成 m=∏Mi=1piki m = ∏ i = 1 M p i k i
用每个 piki p i k i 做模数计算最后EXCRT合并
那么现在模数 Mod=piki M o d = p i k i
计算s的排名,按位枚举i,计算1~i-1位与s相同,第i位< s的序列数,最后+1
令p[i]表示位置i在序列里排第p[i]大,c[i]表示i~n中,序列第i大的数目,那么对于i,有 ans=∑p[i]−1j=1(n−i)!(c[j]−1)!∏nk=1[k!=j]c[k]! a n s = ∑ j = 1 p [ i ] − 1 ( n − i ) ! ( c [ j ] − 1 ) ! ∏ k = 1 n [ k ! = j ] c [ k ] !
上下同乘c[j],有 ans=(n−i)!∏nk=1c[k]!∑p[i]−1j=1c[j] a n s = ( n − i ) ! ∏ k = 1 n c [ k ] ! ∑ j = 1 p [ i ] − 1 c [ j ]
于是用树状数组维护一下,i扫过去顺便维护前面的常数就行了
注意因为模数是 piki p i k i ,维护计算时要把 pi p i 这个因子单独提出来计算最后再乘回去,其他正常用欧拉定理算逆元
code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
inline void read(int &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int exgcd(int a,int b,int &x,int &y)
{
if(!a)
{
x=0,y=1; return b;
}
int tx,ty,d=exgcd(b%a,a,tx,ty);
x=ty-b/a*tx;
y=tx;
return d;
}
int pw(int x,int k,int Mod)
{
int re=1;
for(;k;k>>=1,x=(ll)x*x%Mod) if(k&1)
re=(ll)re*x%Mod;
return re;
}
const int maxn = 310000;
int n,m,mod,Mod,modk,u;
struct node{int x,i;}a[maxn];
inline bool cmpx(const node x,const node y){return x.xinline bool cmpi(const node x,const node y){return x.iint inv[maxn];
void pre()
{
inv[1]=1; int phi=Mod/mod*(mod-1);
for(int i=2;i<=n;i++) if(i%mod) inv[i]=pw(i,phi-1,Mod);
}
int num[maxn],s[maxn];
void add(int x,int c){for(;x<=u;x+=lowbit(x))s[x]+=c; return;}
int query(int x){int re=0;for(;x;x-=lowbit(x))re+=s[x];return re;}
int nowki,now;
int solve()
{
int re=0; pre();
now=1; nowki=0;
for(int i=1;i<=n;i++)
{
num[a[i].x]++;
int j=i; while(j%mod==0) nowki++,j/=mod;
now=(ll)now*j%Mod;
}
for(int i=1;i<=u;i++)
{
add(i,num[i]);
for(int j=1;j<=num[i];j++)
{
int k=j; while(k%mod==0) k/=mod,nowki--;
now=(ll)now*inv[k]%Mod;
}
}
for(int i=1;i<=n;i++)
{
int k=n-i+1; while(k%mod==0) k/=mod,nowki--;
now=(ll)now*inv[k]%Mod;
int tk=nowki<0?pw(mod,-nowki,3*n):pw(mod,nowki,Mod);
int qt=query(a[i].x-1);
int temp=nowki<0?(ll)qt/tk*now%Mod:(ll)qt*now%Mod*tk%Mod;
re+=temp; if(re>=Mod) re-=Mod;
k=num[a[i].x]; while(k%mod==0) k/=mod,nowki++;
now=(ll)now*k%Mod;
num[a[i].x]--; add(a[i].x,-1);
}
return re;
}
int ans[maxn],M[maxn],ki[maxn],tp;
int EXCRT()
{
int qm=sqrt(m)+1; tp=0;
for(int i=2;i<=qm&&m!=1;i++) if(m%i==0)
{
M[++tp]=i;
while(m%i==0) ki[tp]++,m/=i;
}
if(m>1) M[++tp]=m,ki[tp]=1;
int re,rem;
for(int i=1;i<=tp;i++)
{
mod=M[i],modk=ki[i],Mod=1;
for(int j=1;j<=modk;j++) Mod*=mod;
int tmp=solve();
if(i==1) re=tmp,rem=Mod;
else
{
int tx,ty; exgcd(rem,Mod,tx,ty);
Mod*=rem;
re=((ll)tx*rem*(tmp-re)+re)%Mod;
if(re<0) re+=Mod; rem=Mod;
}
}
return (re+1)%Mod;
}
int main()
{
read(n); read(m);
for(int i=1;i<=n;i++) read(a[i].x),a[i].i=i;
sort(a+1,a+n+1,cmpx);
for(int i=1,las=0;i<=n;i++)
{
if(las!=a[i].x) ++u;
las=a[i].x; a[i].x=u;
}
sort(a+1,a+n+1,cmpi);
printf("%d\n",EXCRT());
return 0;
}