51nod 1203 jzplcm

长度为N的正整数序列S,有Q次询问,每次询问一段区间内所有数的lcm(即最小公倍数)。由于答案可能很大,输出答案Mod 10^9 + 7。

例如:2 3 4 5,询问[1,3]区间的最小公倍数为2 3 4的最小公倍数 = 12。

Input

第1行:两个整数,N, Q,中间用空格分隔,N为数列长度,Q为询问数量。(2 <= N, Q <= 50000)
第2 - N + 1行:每行1个整数,对应数列中的元素(1 <= S[i] <= 50000)
第N + 2 - N + Q + 1行:每行2个数,l, r,表示询问下标i在[l, r]范围内的S[i]的最小公倍数。(1 <= l <= r <= N)

Output

输出共Q行,对应询问区间的最小公倍数Mod 10^9 + 7。

Input示例

3 3
123
234
345
1 2
2 3
1 3

Output示例

9594
26910
1103310

由于ai很小可以用各种方法乱搞,但这是一道论文题,原题的ai有1e9;我们考虑这种有关lcm和gcd的题一种常用的处理方法就是分解质因数,这个题我们相当于是要求每个质因子的幂的最大值;这个就很皮了,因为区间中不同质因子的数量是可能很多的,一个个枚举质因子肯定是假的;我们可以考虑干这样一个骚操作,我们分解质因数的时候,我们就真的把他分解,比如说这个数有p^q,那么我们就拆为p^1,p^2,p^3,...,p^q,这么多个数,然后每个数的权值为p,然后问题转化为区间中不同的数的乘积;这样显然是对的,因为我们假设p这个质因子的最大次幂为q,那么会有p这个数会乘q次,因为有p^1,p^2,p^3...p^q每次都乘了p,满足lcm的定义;于是我们发现这是一个经典的问题,对于每个数我们肯定是在他第一次出现在区间中的时候计算贡献,那么我们用类似HH的项链和采花的套路,用一个la[i],表示i位置上的数上一次出现的位置;于是我们变为了询问[l,r]中la[i]<l的数的乘积,我们把询问按照右端点排序用树状数组维护前缀乘积即可,具体实现方法和采花类似;论文链接里面还有各种做法,以及题目的分析过程
//MADE BY QT666
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N=300050;
const int Mod=1e9+7;
int n,q,la[N],prime[N],tot,vis[N],a[N],b[N*20],v[N*20],tt,st[N],ed[N];
vector<int> p[N];
void pre(){
    for(int i=2;i<=100000;i++){
	if(!vis[i]) prime[++tot]=i;
	for(int j=i;j<=100000;j+=i) vis[j]=1;
    }
    for(int i=1;i<=tot;i++){
	for(int j=prime[i];j<=100000;j+=prime[i]) p[j].push_back(prime[i]);
    }
}
struct data{
    int l,r,id;
}Q[N];
int last[N];
bool cmp(const data &a,const data &b){
    return a.r<b.r;
}
ll tr[N*20],ans[N];
int lowbit(int x){return x&-x;}
void update(int x,ll v){
    if(x==0) return;
    for(int i=x;i<=tt;i+=lowbit(i)) (tr[i]*=v)%=Mod;
}
ll query(int x){
    ll ret=1;
    for(int i=x;i;i-=lowbit(i)){
	(ret*=1ll*tr[i])%=Mod;
    }
    return ret;
}
ll qpow(ll x,ll y){
    ll ret=1;
    while(y){
	if(y&1) (ret*=x)%=Mod;
	(x*=x)%=Mod;y>>=1;
    }
    return ret;
}
int main(){
    scanf("%d%d",&n,&q);pre();
    for(int i=1;i<=n;i++){
	scanf("%d",&a[i]);
	int x=a[i];st[i]=tt+1;
	for(int j=0;j<p[a[i]].size();j++){
	    int y=p[a[i]][j],z=p[a[i]][j];
	    while(x%y==0){
		b[++tt]=z;v[tt]=y;x/=y;z*=y;
	    }
	}
	ed[i]=tt;
    }
    for(int i=1;i<=q;i++){
	scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].l=st[Q[i].l],Q[i].r=ed[Q[i].r],Q[i].id=i;
    }
    for(int i=1;i<=tt;i++) la[i]=last[b[i]],last[b[i]]=i;
    sort(Q+1,Q+1+q,cmp);int l=1;
    tr[0]=1;
    for(int i=1;i<=tt;i++) tr[i]=1;
    for(int i=1;i<=q;i++){
	while(l<=Q[i].r){
	    update(la[l],qpow(v[l],Mod-2)),update(l,v[l]);l++;
	}
	ans[Q[i].id]=query(Q[i].r)*qpow(query(Q[i].l-1),Mod-2)%Mod;
    }
    for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
    return 0;
}
时间: 2024-10-17 00:11:33

51nod 1203 jzplcm的相关文章

51Nod1203 2012集训队答辩 JZPLCM

A1339. JZPLCM(顾昱洲) 时间限制:3.0s   内存限制:256.0MB 试题来源 2012中国国家集训队命题答辩 问题描述 给定一长度为n的正整数序列a,有q次询问,每次询问一段区间内所有数的lcm(即最小公倍数).由于答案可能很大,输出答案模1000000007. 输入格式 第一行,两个整数,n, q,分别表示数列长度和询问个数. 下面n行,每行一个整数,第i行的整数为ai. 下面q行,每行两个整数l, r,表示询问下标i在[l, r]范围内的ai的lcm. 输出格式 q行.对

51nod 1201 整数划分(dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1201 题解:显然是一道dp,不妨设dp[i][j]表示数字i分成j个一共有几种分法. 那么转移方程式为: dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] 表示将i - 1划分为j个数,然后j个数都+1 还是不重复,将i - 1划分为j - 1个数,然后j - 1个数都+1,再加上1这个数. 然后就是j的范围要知道1+2+

51nod 1138 连续整数的和(数学)

题目描述: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1138 给出一个正整数N,将N写为若干个连续数字和的形式(长度 >= 2).例如N = 15,可以写为1 + 2 + 3 + 4 + 5,也可以写为4 + 5 + 6,或7 + 8.如果不能写为若干个连续整数的和,则输出No Solution. Input 输入1个数N(3 <= N <= 10^9). OutPut 输出连续整数中的第1个数,如果有多

TLS 协议所定义的严重错误代码是 10。Windows SChannel 错误状态是 1203

windows 2012 操作系统下面报36888/36887. 生成了一个严重警告并将其发送到远程终结点.这会导致连接终止.TLS 协议所定义的严重错误代码是 10.Windows SChannel 错误状态是 1203. 从远程终点接收到一个严重警告.TLS 协议所定义的严重警告代码为 48. 其实schannel的事件录入是分成4个等级的: Logging options The default value for Schannel event logging is 0×0000 in W

51nod 1463 找朋友(线段树+离线处理)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463 题意: 思路: 好题! 先对所有查询进行离线处理,按照右区间排序,因为k一共最多只有10个,所有在该区间内的B数组,每次枚举K值,通过这样的方式来得到另外一个B值.但是这样得到的B值它在B数组中的位置必须在当前数的左边.如下图:(j为当前数在B数组中的位置,pos为计算得到的另一个B值在数组中的位置) 这两个数的和记录在pos中,这里pos的位置必须在j的左边,假

51nod 1437

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1437 1437 迈克步 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 有n只熊.他们站成一排队伍,从左到右依次1到n编号.第i只熊的高度是ai. 一组熊指的队伍中连续的一个子段.组的大小就是熊的数目.而组的力量就是这一组熊中最小的高度. 迈克想知道对于所有的组大小为x(1 ≤ x ≤ n

51nod 1272 思维/线段树

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1272 1272 最大距离 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 给出一个长度为N的整数数组A,对于每一个数组元素,如果他后面存在大于等于该元素的数,则这两个数可以组成一对.每个元素和自己也可以组成一对.例如:{5, 3, 6, 3, 4, 2},可以组成11对,如下(数字为下标):

51nod 1406 位运算/dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1406 1406 与查询 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 有n个整数.输出他之中和x相与之后结果为x的有多少个.x从0到1,000,000 Input 第一行输入一个整数n.(1<=n<=1,000,000). 第二行有n个整数a[0],a[1],a[2],...a[n-1

51nod 1307 绳子与重物(并查集水了一发)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1307 题意: 思路: 可以直接二分答案,然后dfs. 因为标签是并查集,所以我考虑了一下并查集,利用并查集不断向上回溯加负重,居然过了,只能说数据有点水. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #incl