CF594D题解

我不会数据结构/kk

我想题意应该十分清楚了。

我们知道 \(\varphi(p^k)=p^{k-1}(p-1)\),那么我们考虑将一个询问下放到右端点,然后往右移动右端点并更新每个左端点到右端点的答案。

这就变得很容易了。最开始所有位置的答案都是 \(1\)

加入一个数 \(a\) 的时候,因为积性函数可以拆成质数幂处的积性函数之积,所以我们这里也考虑拆成质数幂。

然后记录每一个质因子上一次出现的位置,假设为 \(x\),现在的右端点为 \(i\),那么我们令 \((x,i]\) 乘上 \(p-1\)\([1,x]\) 乘上 \(p\),剩下的位置乘上 \(p^{k-1}\)

可以知道复杂度是 \(O(n\log n\frac {\log V}{\log\log V})\) 的。这个复杂度不知道是在哪儿看到的,反正 1e6 以内绝对不会超过 7。

这个拿线段树做就好了。

然后我们发现是单点查询,所以对标记可持久化。然后使用 zkw 线段树加上快读你就可以拿到 lg 最优解。

甚至能在 CF 上面卡进第一页。。。

实际上还有更为厉害的方法。。。

考虑每个位置的初始值都是 \(a_i\),每次往右扫时将 \(p\) 变为 \(p-1\),线段树的操作次数是我的三分之一。。。

而且这个玩意儿是可以使用树状数组的。。。

不管怎样先把我的代码挂在这里了:

#include<iostream>
#include<cctype>
#include<vector>
typedef unsigned ui;
const ui M=2e5+5,mod=1e9+7;
ui n,m,G,a[M],l[M],r[M],ans[M],prod[M<<2];ui top,pri[M*5],pos[M*5],lst[M*5];std::vector<ui>id[M];
char _input[1<<25|1],_output[1<<25|1],*_p1=_input,*_p2=_output;
inline ui read(){
	ui n(0);char s;while(!isdigit(s=*_p1++));while(n=n*10+(s&15),isdigit(s=*_p1++));return n;
}
inline void write(ui&n){
	static char s[10];ui top(0);while(s[++top]=n%10^48,n/=10);while(*_p2++=s[top],--top);
}
inline void sieve(const ui&M){
	ui i,j,x;
	for(i=2;i<=M;++i){
		if(!pos[i])pri[pos[i]=++top]=i;
		for(j=1;j<=pos[i]&&(x=i*pri[j])<=M;++j)pos[x]=j;
	}
}
void Modify(ui l,ui r,const ui&V){
	for(l+=G-1,r+=G+1;l^r^1;l>>=1,r>>=1){
		if(~l&1)prod[l^1]=1ull*prod[l^1]*V%mod;
		if(r&1)prod[r^1]=1ull*prod[r^1]*V%mod;
	}
}
inline ui Query(ui x){
	ui ans(1);x+=G;while(x)ans=1ull*ans*prod[x]%mod,x>>=1;return ans;
}
signed main(){
	std::cin.read(_input,sizeof _input);
	ui i,x(0),y,t;n=read();for(G=1;G<=n+1;G<<=1);for(i=1;i<=n+G;++i)prod[i]=1;
	for(i=1;i<=n;++i)(a[i]=read())>x&&(x=a[i]);Build(1);sieve(x);m=read();
	for(i=1;i<=m;++i)l[i]=read(),r[i]=read(),id[r[i]].push_back(i);
	for(i=1;i<=n;++i){
		for(x=a[i];x^1;){
			if(pos[x]^1)Modify(lst[pos[x]]+1,i,pri[pos[x]]-1);if(lst[pos[x]])Modify(1,lst[pos[x]],pri[pos[x]]);
			lst[y=pos[x]]=i;t=1;while(pos[x/pri[y]]==pos[x])t*=pri[y],x/=pri[y];x/=pri[y];if(t^1)Modify(1,i,t);
		}
		for(ui&ID:id[i])ans[ID]=Query(l[ID]);
	}
	for(i=1;i<=m;++i)write(ans[i]),*_p2++=10;std::cout.write(_output,_p2-_output);
}
posted @ 2022-01-11 15:42  Prean  阅读(42)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};