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 ...
随机推荐
- illuminate/routing 源码分析之注册路由
我们知道,在 Laravel 世界里,外界传进来一个 Request 时,会被 Kernel 处理并返回给外界一个 Response.Kernel 在处理 Request 时,会调用 illumina ...
- LearnPython笔记:ex48 代码
赶紧写上 ,一定有人着急要看,啊哈哈哈哈,嘻嘻 哈哈 不枉我起了个大早 利用什么碎片时间啊,真正能深入学习的,是需要大段大段不被打断的时间 1. 完全实现了如下几种输入数据: 2. 遗留:最后一个el ...
- Python单例模式的实现方式
一.单例类 单例模式(Singleton Pattern)是 Python 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类 ...
- Vue.Draggable实现拖拽效果(采坑小记)
之前有写过Vue.Draggable实现拖拽效果(快速使用)(http://www.cnblogs.com/songdongdong/p/6928945.html)最近项目中要用到这个拖拽的效果,当产 ...
- 洛谷 3979 BZOJ 3083 遥远的国度
[题解] 这道题除去根操作就是普通的树链剖分了.但是有换根操作怎么处理呢? 我们可以发现如果现在的根不在查询的点的子树里,那么对本次查询没有影响.如果现在的跟在查询的点x的子树里,那么答案将变为整棵树 ...
- 【Codeforces 466B】Wonder Room
[链接] 我是链接,点我呀:) [题意] 让你把长为a,宽为b的房间扩大(长和宽都能扩大). 使得它的面积达到6*n 问你最小的能满足要求的面积是多少 输出对应的a和b [题解] 假设a< b ...
- MTK平台系统稳定性分析
目录 1:简介 2:怎么抓取和分析log 3:怎么确定问题点 简介 系统稳定性目前主要是解决系统死机重启. 分为两部分:Android /kernel Kernel 分析需要的文件和工具: Mtklo ...
- 邮票(codevs 2033)
题目描述 Description 已知一个 N 枚邮票的面值集合(如,{1 分,3 分})和一个上限 K —— 表示信封上能够贴 K 张邮票.计算从 1 到 M 的最大连续可贴出的邮资. 例如,假设有 ...
- android中listview点击事件的监听实现
listview_bookmark.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public vo ...
- 7、Java并发性和多线程-如何创建并运行线程
以下内容转自http://ifeve.com/creating-and-starting-java-threads/: Java线程类也是一个object类,它的实例都继承自java.lang.Thr ...