试题来源

  2012中国国家集训队命题答辩

问题描述

  给定一长度为n的正整数序列a,有q次询问,每次询问一段区间内所有数的lcm(即最小公倍数)。由于答案可能很大,输出答案模1000000007。

输入格式

  第一行,两个整数,n, q,分别表示数列长度和询问个数。
  下面n行,每行一个整数,第i行的整数为ai。
  下面q行,每行两个整数l, r,表示询问下标i在[l, r]范围内的ai的lcm。

输出格式

  q行。对于每个询问,输出一行,表示对应的答案。

样例输入

3 3
123
234
345
1 2
2 3
1 3

样例输出

9594
26910
1103310

数据规模和约定

测试数据编号 规模和约定
1, 2 n, q<=1000
3, 4 n, q<=5000
5, 6 n, q<=20000
7, 8 n, q<=30000
9, 10 n, q<=40000
11, 12 n, q<=50000
13, 14 n, q<=80000
15, 16 n, q<=100000
17, 18, 19, 20 n, q<=100000 数列a中每个数能表示为不超过100的素数的积

对于所有测试点,数列a中每个数满足1<=ai<=1000000000。


求LCM会爆LL,所以可以考虑分解质因数然后求最大幂然后乘起来。

40分算法:

对于最后四个点:
考虑对每个素数的幂建一个ST表,则答案是每个素数的幂的区间最大值,乘起来就行了。复杂度O(25∗nlogn+25q)O(25*nlogn+25q)。

对于前四个点:
暴力分解质因数,求最大的幂。复杂度O(nqlogn)O(nqlogn)。

60分算法:

考虑离线莫队。发现每次区间转移相当于删除/加入log个质数,最后询问是询问每个质数的最大的幂,可以用平衡树来维护,复杂度O(nn√log2n)O(n \sqrt n \log^2 n)。

100分算法:

考虑把一个数拆成多个质数相乘,若有一个因子是pkp^k,则拆成k个数,分别为p1,p2...pkp^1,p^2...p^k,每个数的权值都为p。这样转化成询问区间内不同的数的权值的乘积。

正确性:px!=py (x!=y)p^x!=p^y \ (x != y),若区间内同时出现两个数都有p的因子,则幂高的把幂低的覆盖掉了,每次都是统计的幂最高的数的贡献。

转化的问题可以离线+树状数组求解。

做法:

对于一个数x,记它上一次出现的位置为last[x],x的权值是val[x]。
离线操作是按右端点排序,然后左端点只负责询问,右端点的右移是不断加点的过程。
考虑前缀的区间减法,这样就能树状数组了。
每次加入一个数x,则要让last[x]=last[x]∗1/val[x]last[x]=last[x]*1/val[x],当前位置乘val[x]。支持的查询操作是查询前缀的乘积,然后求个逆元就行了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;typedef long long LL;
const int SZ = 3000010;
const int INF = 1000000010;
const int mod = 1000000007;int tot = 0,cnt = 0;
struct squ{int id,num,val,last;
}a[SZ];struct que{int l,r,id;LL ans;
}ask[SZ];bool cmp(que a,que b) { return a.r < b.r; }
bool cmp2(que a,que b) { return a.id < b.id; }map<int,int> mp; //分配种类 namespace init{bool vis[SZ];int pri[SZ];void gen(int n){vis[1] = 1;for(int i = 2,tot = 0;i <= n;i ++){if(!vis[i]) pri[++ tot] = i;for(int j = 1,m;j <= tot && (m = i * pri[j]) <= n;j ++){vis[m] = 1;if(i % pri[j] == 0) break;}}}void fj(int x,int id){for(int i = 1;(LL)pri[i] * pri[i] <= x;i ++){int t = 1;while(x % pri[i] == 0){t = t * pri[i];if(!mp[t]) mp[t] = ++ cnt;a[++ tot] = (squ){id,mp[t],pri[i],0};x /= pri[i];}}if(x != 1){if(!mp[x]) mp[x] = ++ cnt;a[++ tot] = (squ){id,mp[x],x,0};}}
}LL sum[SZ];
int n,m;void mult(int x,int d)
{if(x == 0) return ;for(int i = x;i <= n;i += i & -i)sum[i] = (LL)sum[i] * d % mod;
}int ask_ans(int x)
{int ans = 1;for(int i = x;i > 0;i -= i & -i)ans = (LL)ans * sum[i] % mod;return ans;
}LL ksm(LL a,LL b)
{LL ans = 1;while(b){if(b & 1) ans = (LL)ans * a % mod;a = (LL)a * a % mod;b >>= 1;}return ans;
}int ni(int x)
{return ksm(x,mod - 2);
}int last[SZ];int main()
{scanf("%d%d",&n,&m);init :: gen(100000);for(int i = 1,x;i <= n;i ++)scanf("%d",&x),init :: fj(x,i);for(int i = 1;i <= n;i ++)sum[i] = 1;for(int i = 1;i <= tot;i ++)a[i].last = last[a[i].num],last[a[i].num] = a[i].id;for(int i = 1;i <= m;i ++)scanf("%d%d",&ask[i].l,&ask[i].r),ask[i].id = i;sort(ask + 1,ask + 1 + m,cmp);for(int i = 1,j = 1,k = 1;i <= n;i ++){while(j <= tot && a[j].id == i)mult(i,a[j].val),mult(a[j].last,ni(a[j].val)),j ++;while(k <= m && ask[k].r == i)ask[k].ans = (LL)ask_ans(ask[k].r) * ni(ask_ans(ask[k].l - 1)) % mod,k ++;}sort(ask + 1,ask + 1 + m,cmp2);for(int i = 1;i <= m;i ++)printf("%lld\n",ask[i].ans);return 0;
}

【TsinsenA1339】JZPLCM(顾昱洲) 树状数组相关推荐

  1. 差分+树状数组 线段树【P2357】 守墓人

    题目描述-->p2357 守墓人 敲了一遍线段树,水过. 树状数组分析 主要思路: 差分 简单介绍一下差分(详细概念太麻烦,看下面. 给定一个数组 7 8 6 5 1 8 18 20 35 // ...

  2. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  3. Color the ball(HDU1556)树状数组

    每次对区间内气球进行一次染色,求n次操作后后所有气球染色次数. 树状数组,上下区间更新都可以,差别不大. 1.对于[x,y]区间,对第x-1位减1,第y位加1,之后向上统计 #include<b ...

  4. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  5. Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)

    题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...

  6. poj_3067 树状数组

    题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M.现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个 ...

  7. hdu 1166 敌兵布阵(树状数组)

    题意:区间和 思路:树状数组 #include<iostream> #include<stdio.h> #include<string.h> using names ...

  8. Equalizing Two Strings 冒泡排序or树状数组

    首先考虑排序后相等 如果排序后相等的话就只考虑reverse长度为2的,所以a或者b排序后存在相邻两个字母相等的话就puts YES,n>26也直接puts YES 不然的话就假设c为a,b排完 ...

  9. Hdu 6534 Chika and Friendly Pairs 莫队算法+树状数组

    题目链接 题意求给区间[L,R]中有少对(i,j)满足i<j且abs(a[i]-a[j])<=k. 首先来说暴力的方法就是离散化,然后用树状数组来维护,但是m次询问,m很大,所以说一定会t ...

  10. HDU - 5877 Weak Pair 2016 ACM/ICPC 大连网络赛 J题 dfs+树状数组+离散化

    题目链接 You are given a rootedrooted tree of NN nodes, labeled from 1 to NN. To the iith node a non-neg ...

最新文章

  1. linux c 环境变量函数 getenv putenv 简介
  2. MySQL Workbench 怎么创建数据库
  3. G面经prepare: Set Intersection Set Difference
  4. 差动机器人毕业设计_双轮差动机器人曲线算法设计与实现
  5. C语言string.h文件函数汇总详解
  6. HTML5 上传图片预览
  7. glClearDepth
  8. linux grep 匹配空格_17 个案例,5 分钟简单搞定 Linux 正则表达式!
  9. 统计app用户在线时长_「云工作普及系列」2.如何实时统计工作时长,提高工作效率
  10. Nacos Spring Boot 快速开始
  11. 贴吧备份到本地浏览html,获取贴吧对应页html及写入文件
  12. 南昌大学计算机接收调剂的条件,关于2018年河南昌大学学硕士研究生接收调剂程序及要求的须知详情...
  13. Spring AOP异常处理(error at ::0 formal unbound in pointcut)
  14. 前端设备通过Ehome协议接入EasyCVR平台无法播放问题解决
  15. 架构篇--系统监控--spring-boot2.0.X 系统原生信息监控,SQL信息监控,cpu温度监控报警,cup磁盘内存使用率监控报警,自定义端点监控以及子节点获取,系统异常邮件通知
  16. 2021-08-23
  17. 简单二阶有源滤波电路分析
  18. 6种php加密解密方法
  19. 公共基础知识中计算机知识,公共基础知识之计算机知识总结
  20. 阿齐索-对接淘宝第三方平台

热门文章

  1. 全国各省会城市经纬度(包含港澳台)
  2. anki android 导入路径,3.1 导入卡片
  3. 真正的落雷(打印图形练习题)C语言
  4. 《计算机组成原理》作业,《计算机组成原理》作业一解答.doc
  5. excel如何隔行填充颜色
  6. python能做什么工作好-python可以做什么工作
  7. 各大云服务厂商 轻量应用服务器 性能评测对比,阿里云、腾讯云、华为云、Ucloud
  8. 腾讯QQ会员技术团队:人人都可以做深度学习应用:入门篇(下)
  9. nacos 2.0 Scanner SubTypesScanner was not configured
  10. 饭店流量预测-多表关联+lightgbm