这个东西读完题之后,就能知道我们要逐位计算贡献.
推一下式子,会发现,这一位的贡献,是当前剩余的数字形成的序列的总数,乘上所剩数字中小于s上这一位的数的个数与所剩数字的总数的比.
所以我们维护“当前剩余的数字形成的序列的总数”以及权值数组的前缀和就好了.
后者可以用树状数组维护,前者可以用一个变量维护.
但是!!!!!模数不是质数!!!!!
这就很坑爹,网上的人基本上都是把模数质因数分解后,对于每一种质因数计算一次答案,最后再crt计算答案.
然而,作为一只**,我用长得像二叉堆,但是维护信息上又有点像平衡树的二叉树维护变量,直接以m为模数计算出答案.
我的思路是这样的,我们维护数字,只有乘和除,既然不能算逆元,那么我们就维护这个数字的所有可能含有的质数的个数,并且对于所有的质数建立树形结构,每个点除了维护其自己信息以外,还维护了其子树乘积,那么树根的子树乘积就是这个数,而我们乘(除)一个数的时候,将乘(除)的数质因子拆分,对于每个质因子,修改他在树中的信息以及他的在树中的祖先的信息,这样的复杂度是O(nlog^2n)的.
一开始我直接按照质数的大小建立BST,卡了半天常数才过,后来发现,我不如按照质数大小建立小根堆,这样使用频繁的质数(小的质数)的深度就会变小,于是我一下子从bzoj倒数第一滚到大众时间.

#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
typedef long long LL;
char xB[(<<)+],*xS,*xT;
#define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline void read(int &x){
R char ch=gtc;
for(x=;ch<''||ch>'';ch=gtc);
for(;ch>=''&&ch<='';x=(x*)+ch-'',ch=gtc);
}
const int N=;
inline int gcd(int x,int y){return !x?y:gcd(y%x,x);}
int len,prime[N/+],min[N+],size[N/+];
bool isnot[N+];
int n,m,ans,P,lim;
int mii[N*+],*begin[N/+];
#define mi(a,b) (*(begin[(a)]+(b)))
int a[N+],tree[N+],cnt[N+];
inline void U(R int pos,int key){
for(;pos<=N;pos+=pos&(-pos))
tree[pos]+=key;
}
inline int Q(R int pos){
R int ret=;
for(;pos>;pos-=pos&(-pos))
ret+=tree[pos];
return ret;
}
inline void get(R int x,int opt){
while(min[x])
size[min[x]]+=opt,x/=prime[min[x]];
}
struct BST{
BST *ch[],*f;
int id,key;
}node[N+],*root;
#define pushup(p) (p->key=(LL)mi(p->id,size[p->id])*p->ch[0]->key%P*p->ch[1]->key%P)
#define mid ((l+r)>>1)
inline void build(BST *&p,BST *fa,int id){
p=node+id,p->key=;
if(id>len)return;
p->f=fa,p->id=id;
build(p->ch[],p,id<<);
build(p->ch[],p,(id<<)|);
pushup(p);
}
inline void update(int x){
R BST *p=node+x;
while(p)pushup(p),p=p->f;
}
inline void update(R int x,int opt){
if(x==)return;
R int last=;
while(min[x]){
size[min[x]]+=opt;
if(last&&min[x]!=last)update(last);
last=min[x];
x/=prime[min[x]];
}
update(last);
}
int main(){
//freopen("rio.in","r",stdin);
R int i,j;
read(n),read(P),lim=n;
isnot[]=true,min[]=;
for(i=;i<=lim;++i){
if(!isnot[i])prime[++len]=i,min[i]=len;
for(j=;prime[j]*i<=lim;++j){
isnot[prime[j]*i]=true;
min[prime[j]*i]=j;
if(i%prime[j]==)break;
}
}
for(i=;i<=n;++i)read(a[i]),U(a[i],),++cnt[a[i]];
for(i=;i<=n;++i)get(i,);
for(i=;i<=len;++i){
begin[i]=mii+m;
m+=size[i]++;
mi(i,)=;
for(j=;j<=size[i]+;++j)
mi(i,j)=(LL)mi(i,j-)*prime[i]%P;
}
for(i=;i<=N;++i)
for(j=;j<=cnt[i];++j)
get(j,-);
build(root,NULL,);
R int s;
for(i=;i<=n;++i){
s=Q(a[i])-cnt[a[i]];
if(s){
update(s/gcd(s,n-i+),),update((n-i+)/gcd(s,n-i+),-);
ans=(ans+root->key)%P;
update(cnt[a[i]],),update(s,-);
}else{
update(cnt[a[i]],),update(n-i+,-);
}
--cnt[a[i]],U(a[i],-);
}
ans=(ans+)%P;
printf("%d\n",ans);
return ;
}

【BZOJ 1129】[POI2008]Per 二叉堆的更多相关文章

  1. BZOJ 4241: 历史研究——莫队 二叉堆

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4241 题意:N个int范围内的数,M次询问一个区间最大的(数字*出现次数)(加权众数),可以 ...

  2. AC日记——二叉堆练习3 codevs 3110

    3110 二叉堆练习3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 给定N(N≤500,000)和N个整 ...

  3. codevs 3110 二叉堆练习3

    3110 二叉堆练习3 http://codevs.cn/problem/3110/ 题目描述 Description 给定N(N≤500,000)和N个整数(较有序),将其排序后输出. 输入描述 I ...

  4. 数据结构图文解析之:二叉堆详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  5. POJ 2010 - Moo University - Financial Aid 初探数据结构 二叉堆

    考虑到数据结构短板严重,从计算几何换换口味= = 二叉堆 简介 堆总保持每个节点小于(大于)父亲节点.这样的堆被称作大根堆(小根堆). 顾名思义,大根堆的数根是堆内的最大元素. 堆的意义在于能快速O( ...

  6. 二叉堆(一)之 图文解析 和 C语言的实现

    概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...

  7. 二叉堆(二)之 C++的实现

    概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...

  8. 二叉堆(三)之 Java的实现

    概要 前面分别通过C和C++实现了二叉堆,本章给出二叉堆的Java版本.还是那句话,它们的原理一样,择其一了解即可. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的Java实现(完整源码) ...

  9. 二叉堆(binary heap)

    堆(heap) 亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因 ...

随机推荐

  1. 人脸辨识,用树莓派Raspberry Pi实现舵机云台追踪脸孔

    影像辨识作为近年最热门的专业技术之一,广泛用于智慧监视器.车电监控.智慧工厂.生物医疗电子等等:其中,人脸辨识是一个很重要的部分,网络上已经有相当多的资源可供下载使用:于是我们使用舵机云台作为镜头旋转 ...

  2. asp.net的forms身份验证 单用户身份验证

    asp.net的forms身份验证  单用户身份验证 首先要配置Web.config文件 <system.web> <authentication mode="Forms& ...

  3. python 动态获取当前运行的类名和函数名的方法

    一.使用内置方法和修饰器方法获取类名.函数名 python中获取函数名的情况分为内部.外部,从外部的情况好获取,使用指向函数的对象,然后用__name__属性 复制代码代码如下: def a():pa ...

  4. 解决Ubuntu16.04 fatal error: json/json.h: No such file or directory

    参考博客 错误产生 安装json-c库之后,根据GitHub上面的readme文件链接到json-c库时出现以下错误: SDMBNJson.h:9:23: fatal error: json/json ...

  5. 软工实践-Alpha 冲刺 (7/10)

    队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 已经解决登录注册等基本功能的界面. 完成非功能的主界面制作 ...

  6. Python学习 - 入门篇2(更新中)

    前言 学习渠道:慕课网:Python进阶 记录原因:我只是想边上课边做笔记而已,呵呵哒 食用提示:教程环境基于Python 2.x,有些内容在Python 3.x中已经改变 函数式编程 定义:一种抽象 ...

  7. 如何通过JAVA让DB2调用操作系统命令

    引言:我们在工作中常用操作系统命令和DB2命令对数据库做数据的导入.导出等操作,但是DB2不支持复合SQL 语句调用操作系统命令,因此我们需要利用 UDF 来执行SQL 中不可用的操作(例如:执行一些 ...

  8. Mac10.11.2 Apache 服务配置

    系统默认是隐藏apache安装目录的,但我们可以通过“命令行”或者“文件夹前往”的方式找到它.它是安装在系统的私有目录下,也就是/private/etc下面,因为它是隐藏的,所以我们无法通过界面找到它 ...

  9. HDU 2164 Rock, Paper, or Scissors?

    http://acm.hdu.edu.cn/showproblem.php?pid=2164 Problem Description Rock, Paper, Scissors is a two pl ...

  10. saltstack进阶

    查看minion端的文件内容 [root@linux-node2 ~]# cat /etc/resolv.conf # Generated by NetworkManager nameserver 1 ...