【BZOJ 1129】[POI2008]Per 二叉堆
这个东西读完题之后,就能知道我们要逐位计算贡献.
推一下式子,会发现,这一位的贡献,是当前剩余的数字形成的序列的总数,乘上所剩数字中小于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 二叉堆的更多相关文章
- BZOJ 4241: 历史研究——莫队 二叉堆
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4241 题意:N个int范围内的数,M次询问一个区间最大的(数字*出现次数)(加权众数),可以 ...
- AC日记——二叉堆练习3 codevs 3110
3110 二叉堆练习3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description 给定N(N≤500,000)和N个整 ...
- codevs 3110 二叉堆练习3
3110 二叉堆练习3 http://codevs.cn/problem/3110/ 题目描述 Description 给定N(N≤500,000)和N个整数(较有序),将其排序后输出. 输入描述 I ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- POJ 2010 - Moo University - Financial Aid 初探数据结构 二叉堆
考虑到数据结构短板严重,从计算几何换换口味= = 二叉堆 简介 堆总保持每个节点小于(大于)父亲节点.这样的堆被称作大根堆(小根堆). 顾名思义,大根堆的数根是堆内的最大元素. 堆的意义在于能快速O( ...
- 二叉堆(一)之 图文解析 和 C语言的实现
概要 本章介绍二叉堆,二叉堆就是通常我们所说的数据结构中"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本 ...
- 二叉堆(二)之 C++的实现
概要 上一章介绍了堆和二叉堆的基本概念,并通过C语言实现了二叉堆.本章是二叉堆的C++实现. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的C++实现(完整源码)4. 二叉堆的C++测试程 ...
- 二叉堆(三)之 Java的实现
概要 前面分别通过C和C++实现了二叉堆,本章给出二叉堆的Java版本.还是那句话,它们的原理一样,择其一了解即可. 目录1. 二叉堆的介绍2. 二叉堆的图文解析3. 二叉堆的Java实现(完整源码) ...
- 二叉堆(binary heap)
堆(heap) 亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因 ...
随机推荐
- [leetcode-908-Smallest Range I]
Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K, and ...
- python分割文件目录/文件名和后缀
import os file_path = "D:/test/test.py" (filepath,tempfilename) = os.path.split(file_path) ...
- 20172314 蓝墨云课堂实践ASL
由于去跳啦啦操没有上课... 介绍 折半查找,又称作二分查找.这个查找的算法的特点,就是,要求数据要是有序的. 1 ,存储结构一定是顺序存储 2 ,关键字大小必须有序排列 然后,利用这组有序的数据之间 ...
- 事后诸葛亮--Alpha版本总结
目录 设想和目标 计划 资源 变更管理 设计/实现 测试/发布 团队的角色,管理,合作 总结: 本小组和其他组的评分 分工和贡献分 全组讨论的照片 问题 第一组提问回答:爸爸饿了队 第二组提问回答:拖 ...
- Java微笔记(7)
String 类常用方法 注意点: 字符串 str 中字符的索引从0开始,范围为 0 到 str.length()-1 使用 indexOf 进行字符或字符串查找时,如果匹配返回位置索引:如果没有匹配 ...
- [转]Android试验:如果View的ID相同会出现什么效果?
1.实验:通过布局编辑器强行指定两个button id相同,然后在代码中通过findViewById()获得句柄后修改其文本. 实验结果:只有一个button的文本变化了,另一个不受影响. 2.实 ...
- HDU 5269 ZYB loves Xor I Trie树
题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5269 bc:http://bestcoder.hdu.edu.cn/contests/con ...
- ASP.NET MVC 4 内容映射
文章:ASP.NET MVC 4 内容映射 地址:https://msdn.microsoft.com/zh-cn/library/gg416514(v=vs.108).aspx 模型-视图-控制器 ...
- oracle与DB2的一些架构
首先,我们需要理解 Oracle 使用的架构,并理解它与 DB2 的不同之处.图 1 展示了 Oracle 的系统结构.将该图与 图 2 进行比较,后者显示了 DB2 的系统结构.在阅读本文的时候,为 ...
- LAMP环境搭建Wordpress个人博客
LAMP简要介绍 L:LinuxA:Apache(httpd)M:MySQL , MariadbP:php, perl , python 静态资源:图片,文档,视频,HTML代码,CSS代码,js代码 ...