思路:

先copy一下百度百科 作为预备知识吧
多重全排列定义:求r1个1,r2个2,…,rt个t的排列数,设r1+r2+…+rt=n,设此排列数称为多重全排列,表示为$P(n;r1,r2,…,rt)$
$P(n;r1,r2,…,rt)=\frac{n!}{(r1!r2!...rt!)}$

题目是让求s的排名mod m
我们就可以从前往后枚举
前$(i-1)$位跟给出的排列一样 第i位填小于s[i]的数
后面i到n位可以随便填的方案数
(有点像数位DP最后统计的那种感觉.)
设calc[x]是串s中i到n位 x出现的次数
这样枚举到第i位的答案就是$(\Sigma_{j=i}^n{s[j]<s[i]})*\frac{(n-i)!}{(cnt[1]!cnt[2]!...cnt[max—s[x]])}$
(离散化什么的就不用我说了吧)
m不是质数 怎么办
把m拆成$m={p_{1}}^{q_{1}}*{p_{2}}^{q_{2}}...{p_{cnt}}^{q_{cnt}}$
用中国剩余定理搞一搞
把不与$p^q$互质的数单独拎出来算
整体复杂度是$O(nlognlogm)$的
(最好别用线段树.. 常数大)
(CRT和exgcd的时候要时刻注意负数)

//By SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=;
int n,M,u,xx,yy,s[N],cpy[N],tree[N*],Ans[N];
int p[N],ps[N],cnt,fac[N],numb[N],calc[N],pw[N];
void exgcd(int a,int b,int &x,int &y){
if(!b){x=,y=;return;}
exgcd(b,a%b,x,y);
int temp=x;x=y;y=temp-a/b*y;
}
int CRT(int *a,int *m){
int ans=;
for(int i=;i<=cnt;i++){
exgcd(M/m[i],m[i],xx,yy);
ans=(ans+1ll*M/m[i]*xx%M*a[i])%M;
}return (ans+M)%M;
}
void insert(int l,int r,int pos,int num,int wei){
if(l==r){tree[pos]+=wei;return;}
int mid=(l+r)>>,lson=pos<<,rson=pos<<|;
if(mid<num)insert(mid+,r,rson,num,wei);
else insert(l,mid,lson,num,wei);
tree[pos]=tree[lson]+tree[rson];
}
int query(int l,int r,int pos,int L,int R){
if(l>=L&&r<=R)return tree[pos];
int mid=(l+r)>>,lson=pos<<,rson=pos<<|;
if(mid<L)return query(mid+,r,rson,L,R);
else if(mid>=R)return query(l,mid,lson,L,R);
else return query(l,mid,lson,L,R)+query(mid+,r,rson,L,R);
}
void Dec(int m){
for(int i=;i*i<=m;i++)if(m%i==){
p[++cnt]=i,ps[cnt]=;
while(m%i==)m/=i,ps[cnt]*=i;
}if(m!=)p[++cnt]=m,ps[cnt]=m;
}
int inv(int a,int b){exgcd(a,b,xx,yy);return (xx+b)%b;}
void solve(){
for(int T=;T<=cnt;T++){
for(int i=;i<=n;i++){
int temp=i,jy=;while(temp%p[T]==)temp/=p[T],jy++;
fac[i]=1ll*fac[i-]*temp%ps[T];
pw[i]=pw[i-]*p[T]%ps[T];
numb[i]=numb[i-]+jy;
insert(,u,,s[i],),calc[s[i]]++;
}int sum=,sum_inv=;
for(int i=;i<=u;i++)sum+=numb[calc[i]],sum_inv=1ll*sum_inv*inv(fac[calc[i]],ps[T])%ps[T];
for(int i=;i<=n;i++){
Ans[T]=(Ans[T]+1ll*query(,u,,,s[i]-)*fac[n-i]%ps[T]*sum_inv%ps[T]*pw[numb[n-i]-sum])%ps[T];
sum_inv=1ll*sum_inv*fac[calc[s[i]]]%ps[T]*inv(fac[calc[s[i]]-],ps[T])%ps[T];
sum-=numb[calc[s[i]]],calc[s[i]]--,sum+=numb[calc[s[i]]];
insert(,u,,s[i],-);
}(Ans[T]+=)%=ps[T];
}
}
signed main(){
scanf("%d%d",&n,&M);Dec(M);pw[]=fac[]=;
for(int i=;i<=n;i++)scanf("%d",&s[i]),cpy[i]=s[i];
sort(cpy+,cpy++n);u=unique(cpy+,cpy++n)-cpy-;
for(int i=;i<=n;i++)s[i]=lower_bound(cpy+,cpy++u,s[i])-cpy;
solve();printf("%d\n",CRT(Ans,ps));
}

BZOJ 1129 exgcd+CRT+线段树的更多相关文章

  1. Bzoj 2752 高速公路 (期望,线段树)

    Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...

  2. BZOJ.3938.Robot(李超线段树)

    BZOJ UOJ 以时间\(t\)为横坐标,位置\(p\)为纵坐标建坐标系,那每个机器人就是一条\(0\sim INF\)的折线. 用李超线段树维护最大最小值.对于折线分成若干条线段依次插入即可. 最 ...

  3. BZOJ.1558.[JSOI2009]等差数列(线段树 差分)

    BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...

  4. BZOJ 3779: 重组病毒(线段树+lct+树剖)

    题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...

  5. BZOJ 3123 森林(函数式线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...

  6. BZOJ 2124等差子序列 线段树&&hash

    [题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...

  7. Bzoj 3747: [POI2015]Kinoman 线段树

    3747: [POI2015]Kinoman Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 553  Solved: 222[Submit][Stat ...

  8. BZOJ 3155: Preprefix sum( 线段树 )

    刷刷水题... 前缀和的前缀和...显然树状数组可以写...然而我不会, 只能写线段树了 把改变成加, 然后线段树维护前缀和, 某点p加, 会影响前缀和pre(x)(p≤x≤n), 对[p, n]这段 ...

  9. bzoj 1307/1318 玩具 线段树+记录时间戳

    玩具 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 743  Solved: 404[Submit][Status][Discuss] Descrip ...

随机推荐

  1. Webstorm如何配置自动补全前缀--autoprefixer

    我们在写样式代码时,对不同平台会有不同的兼容性写法,会在代码前加前缀,但是手动加前缀很费时间而且很容易弄错.Webstorm编辑器是有自带补全前缀功能的,那为什么还要写这篇配置博客,因为Webstor ...

  2. HDU 1203 背包问题

    题目大意: 根据学校的申请费用,根据已有的钱得到最大的offer率 这里很明显就是一个价值为概率的背包问题 计算两个offer合并的概率 为a + b - a*b #include <cstdi ...

  3. hdu 2255KM算法模板

    #include<stdio.h> #include<string.h> #define N  400 #define inf 0x7fffffff int Max(int a ...

  4. vue.js定义一个一级的路由 ----由浅入深

    #### 定义一个路由- 实例化一个路由并设置路由映射表 - 实例化里面第一个参数 routes 路由映射表 - routes 里面参数 - path 路由的路径 - component 路由对应的组 ...

  5. 轰炸II

    题目背景 本题为轰炸数据加强版 题目描述 一个城市遭到了M次轰炸,每次都炸了一个每条边都与边界平行的矩形 在轰炸后,有N个关键点,指挥官想知道,它们有没有受到过轰炸,如果有,被炸了几次,最后一次是第几 ...

  6. HDU1914(稳定婚姻)

    http://acm.hdu.edu.cn/showproblem.php?pid=1914 思路:Gale-Shapley算法.算法过程是男士不停地求婚,女士不停地拒绝.在每一轮中,每个尚未订婚的男 ...

  7. [codevs 1243][网络提速(最短路分层思想)

    题目:http://dev.codevs.cn/problem/1243/ 分析: 先容易想到将一个点拆成m个点,分别对应不同的边连过去,但是想不到控制加速器数量的办法.看了题解才知道,每个点的分层, ...

  8. 源码分析-react1-根节点渲染

  9. 项目中应用到的框架和技术之三——echarts

    echarts是效果丰富的图表库,当时考虑怎么炫怎么来就引入了这个库来做图表展示,官网:http://echarts.baidu.com 项目里用的比较浅,估且一看吧 代码: this.toChart ...

  10. Java并发:线程安全的单例模式

    转载请注明出处:jiq•钦'stechnical Blog 1.饿汉式 public class Singleton { private final static Singleton INSTANCE ...