BZOJ 1129 exgcd+CRT+线段树
思路:
先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+线段树的更多相关文章
- Bzoj 2752 高速公路 (期望,线段树)
Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...
- BZOJ.3938.Robot(李超线段树)
BZOJ UOJ 以时间\(t\)为横坐标,位置\(p\)为纵坐标建坐标系,那每个机器人就是一条\(0\sim INF\)的折线. 用李超线段树维护最大最小值.对于折线分成若干条线段依次插入即可. 最 ...
- BZOJ.1558.[JSOI2009]等差数列(线段树 差分)
BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...
- BZOJ 3779: 重组病毒(线段树+lct+树剖)
题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...
- BZOJ 3123 森林(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...
- BZOJ 2124等差子序列 线段树&&hash
[题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...
- Bzoj 3747: [POI2015]Kinoman 线段树
3747: [POI2015]Kinoman Time Limit: 60 Sec Memory Limit: 128 MBSubmit: 553 Solved: 222[Submit][Stat ...
- BZOJ 3155: Preprefix sum( 线段树 )
刷刷水题... 前缀和的前缀和...显然树状数组可以写...然而我不会, 只能写线段树了 把改变成加, 然后线段树维护前缀和, 某点p加, 会影响前缀和pre(x)(p≤x≤n), 对[p, n]这段 ...
- bzoj 1307/1318 玩具 线段树+记录时间戳
玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 743 Solved: 404[Submit][Status][Discuss] Descrip ...
随机推荐
- 为什么要有uboot?带你全面分析嵌入式linux系统启动过程中uboot的作用
1.为什么要有uboot 1.1.计算机系统的主要部件 (1)计算机系统就是以CPU为核心来运行的系统.典型的计算机系统有:PC机(台式机+笔记本).嵌入式设备(手机.平板电脑.游戏机).单片机(家用 ...
- 洛谷 2055 BZOJ 1433 [ZJOI2009]假期的宿舍
[题解] 既然是一人对应一床,那么显然可以用二分图匹配来做.俩人认识的话,如果其中一个a是在校学生,另一个b不回家,b就可以向a的床连边(a,b当然也可以是同一个人). 然后如果最大匹配数大于等于需要 ...
- ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer
传送门:https://nanti.jisuanke.com/t/31462 本题是一个树上的问题:结点间路径问题. 给定一个有N×M个结点的网格,并给出结点间建立墙(即拆除边)的代价.花费最小的代价 ...
- Python异常捕捉的一个小问题
问题: names = ['taotao','songwenjing','liu','li']I = iter(names)while True: try: s = next(I) except Ex ...
- 第一个Maven工程的目录结构和文件内容及联网问题
[第一个Maven工程] ①目录结构 Hello |---src |---|---main |---|---|---java |---|---|---resources |---|---test |- ...
- node.js 利用流实现读写同步,边读边写
//10个数 10个字节,每次读4b,写1b let fs=require("fs"); function pipe(source,target) { //先创建可读流,再创建可写 ...
- Linux下汇编语言学习笔记76 ---
这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...
- jd-eclipse插件的安装
一,资源 jd-eclipse-site-1.0.0-RC2.zip 百度网盘链接:https://pan.baidu.com/s/1GTFFY_1jg4k9vjZNE4JliQ 提 ...
- Tomcat配置文件server.xml(转)
前言 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛.server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的 ...
- linux 设置root可以远程登陆
编辑/etc/ssh/sshd_config 设置 PermitRootLogin yes 重启ssh 服务 ubuntu service ssh start