ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF594D】REQ

2020-04-02 11:57:08  阅读:281  来源: 互联网

标签:last int REQ update seg 因子 CF594D ql


题目

题目链接:https://codeforces.com/problemset/problem/594/D
给出一个长度为 \(n\) 的数列,\(Q\) 次询问,每次询问给出 \(l,r\),需要求出 \(\varphi(\prod ^{r}_{i-l}a[i])\bmod p\)。
\(n,Q\leq 200000,a[i]\leq 10^6\)。

思路

考虑到一个数 \(x\) 的质因子不会超过 \(\log x\) 个,所以可以离线按照询问的右端点排序,记录每一个质因子最后出现的位置。
按照右端点排序后,我们对于一个询问 \([l_i,r_i]\),将 \((r_{i-1},r_i]\) 的数分别求质因子,然后找到上一个拥有这个质因子的数,用一个数据结构维护一下,保证对于每一个质因子 \(p\),它的贡献都算在现在询问到的区间的最后一个含有 \(p\) 质因子的数字上。而一个数 \(p\) 的贡献是 \(\frac{p-1}{p}\),所以我们需要一个支持单调修改、区间查询乘积的数据结构,线段树和树状数组都可以的。
如何快速处理出一个数的质因子?在线性筛的时候,我们求出了每个数的最小质因子 \(v\),那么就不断让 \(a[i]\) 除以 \(v[a[i]]\) 即可。
讲的似乎很模糊,看一下这部分代码

for (;j<=ask[i].r;j++)
	for (int k=a[j];k>1;)
	{
		int d=v[k];  //求这一位的质因子
		if (last[d]) seg.update(1,last[d],d);
		if (last[d]) seg.update(1,last[d],inv[d-1]);  //在线段树中将上一个含有这个质因子的位置的贡献消除
		last[d]=j;
		seg.update(1,j,inv[d]);
		seg.update(1,j,d-1);  //维护该质因子的贡献
		while (k%d==0) k/=d;
	}

那么整个问题就迎刃而解了。需要预处理逆元,否则时间复杂度多一个 \(\log n\)。
时间复杂度 \(O(n\log n\log a[i])\)。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=200010,M=1e6+10,MOD=1e9+7;
int n,Q,m,a[N],last[M],v[M],prm[M],inv[M],ans[N];

struct Query
{
	int l,r,id;
}ask[N];

bool cmp(Query x,Query y)
{
	return x.r<y.r;
}

void findprm(int k)
{
	for (int i=2;i<=k;i++)
	{
		if (!v[i]){v[i]=i; prm[++m]=i;}
		for (int j=1;j<=m;j++)
		{
			if (1LL*prm[j]*i>k || v[i]<prm[j]) break;
			v[prm[j]*i]=prm[j];
		}
	}
}

ll fpow(ll x,ll k,ll p)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%p)
		if (k&1) ans=ans*x%p;
	return ans;
}

struct Seg
{
	int l[N*4],r[N*4];
	ll mul[N*4];
	
	void pushup(int x)
	{
		mul[x]=mul[x*2]*mul[x*2+1]%MOD;
	}
	
	void build(int x,int ql,int qr)
	{
		l[x]=ql; r[x]=qr;
		if (ql==qr)
		{
			mul[x]=a[ql];
			return;
		}
		int mid=(ql+qr)>>1;
		build(x*2,ql,mid); build(x*2+1,mid+1,qr);
		pushup(x);
	}
	
	void update(int x,int k,int val)
	{
		if (l[x]==k && r[x]==k)
		{
			mul[x]=mul[x]*val%MOD;
			return;
		}
		int mid=(l[x]+r[x])>>1;
		if (k<=mid) update(x*2,k,val);
			else update(x*2+1,k,val);
		pushup(x);
	}
	
	ll query(int x,int ql,int qr)
	{
		if (l[x]==ql && r[x]==qr)
			return mul[x];
		int mid=(l[x]+r[x])>>1;
		if (qr<=mid) return query(x*2,ql,qr);
		else if (ql>mid) return query(x*2+1,ql,qr);
		else return query(x*2,ql,mid)*query(x*2+1,mid+1,qr)%MOD;
	}
}seg;

int main()
{
	findprm(M-10);
	inv[0]=1;
	for (int i=1;i<=M-10;i++)
		inv[i]=fpow(i,MOD-2,MOD);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	seg.build(1,1,n);
	scanf("%d",&Q);
	for (int i=1;i<=Q;i++)
	{
		scanf("%d%d",&ask[i].l,&ask[i].r);
		ask[i].id=i;
	}
	sort(ask+1,ask+1+Q,cmp);
	for (int i=1,j=1;i<=Q;i++)
	{
		for (;j<=ask[i].r;j++)
			for (int k=a[j];k>1;)
			{
				int d=v[k];
				if (last[d]) seg.update(1,last[d],d);
				if (last[d]) seg.update(1,last[d],inv[d-1]);
				last[d]=j;
				seg.update(1,j,inv[d]);
				seg.update(1,j,d-1);
				while (k%d==0) k/=d;
			}
		ans[ask[i].id]=seg.query(1,ask[i].l,ask[i].r);
	}
	for (int i=1;i<=Q;i++)
		printf("%d\n",ans[i]);
	return 0;
}

标签:last,int,REQ,update,seg,因子,CF594D,ql
来源: https://www.cnblogs.com/stoorz/p/12618622.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有