核桃NOI周赛56 varphi

题目传送门

我们首先要知道一个结论,设 \(d=\gcd(a,b)\),则有:\(\varphi(a\times b)=\dfrac{\varphi(a)\times \varphi(b)\times d}{\varphi(d)}\)

我们不难想到枚举 \(d\) 进行计算。

但是我们会发现一个问题,就是在所有 \(d\) 的倍数中,选出两个数的 \(\gcd\) 只能保证时 \(d\) 的倍数,不能保证一定是 \(d\)

这里又有一个结论:\(\dfrac{d}{\varphi(d)}\le \dfrac{k\times d}{\varphi(k\times d)}\),也就是说,如果我们强制认为每对数的 \(\gcd\) 都是 \(d\),答案一定不会被算大。

现在我们有一个做法,对于每组询问枚举 \(d\),找出 \(\varphi\) 最大的两个计算贡献(注意这里不论实际 \(\gcd\) 是多少,我们都认为是 \(d\))。

但是这个做法还是太慢了,我们考虑优化。

注意到,如果 \((x,y)\)\([x,y]\) 中最大的贡献的话,一定不存在 \(z\),使得 \(\varphi(z)>max(\varphi(x),\varphi(y))\),否则我们用 \(z\) 匹配上 \(x,y\)\(\varphi\) 大的那一个一定更优。

这样我们可能贡献的对数就很少了,可以直接把询问离线下来然后对 \(l\) 从大到小扫描线,再用一个线段树维护一下当前合法区间内贡献最大值即可。

AC code:

#include<bits/stdc++.h>
#define int long long
#define N 500005
#define pii pair<int,int>
#define x first
#define y second
#define mod 1000000007
#define inf 2e18
using namespace std;
int T=1,n,Q,a[N],phi[N],pre[N],cnt,pos[N],res[N];
bool st[N];
vector<pii>v[N];
struct node{
	int l,r,id;
}q[N];
void init(){
    phi[1]=1;
    for(int i=2;i<N;i++){
        if(!st[i]){
            pre[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt&&pre[j]*i<N;j++){
            st[pre[j]*i]=1;
            if(i%pre[j]==0){
                phi[i*pre[j]]=phi[i]*pre[j];
                break;
            }
            phi[i*pre[j]]=phi[i]*(pre[j]-1);
        }
    }
}
int gcd(int a,int b){
	return b?gcd(b,a%b):a;
}
struct sgt{
    int tr[N<<2];
    void pushup(int u){
    	tr[u]=max(tr[u<<1],tr[u<<1|1]);
	}
	void modify(int u,int l,int r,int p,int v){
		if(l==r){
			tr[u]=max(tr[u],v);
			return;
		}
		int mid=l+r>>1;
		if(p<=mid)modify(u<<1,l,mid,p,v);
		else modify(u<<1|1,mid+1,r,p,v);
		pushup(u);
	}
	int qry(int u,int l,int r,int L,int R){
		if(l>=L&&r<=R)return tr[u];
		int mid=l+r>>1;
		int res=0;
		if(L<=mid)res=max(res,qry(u<<1,l,mid,L,R));
		if(R>mid)res=max(res,qry(u<<1|1,mid+1,r,L,R));
		return res;
	}
}sgt;
void solve(int cs){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pos[a[i]]=i;
    }
    cin>>Q;
    for(int d=1;d<=n;d++){
        vector<int>e;
        for(int i=d;i<=n;i+=d){
            e.push_back(pos[i]);
        }
        sort(e.begin(),e.end());
        stack<int>stk;
		for(int i=0;i<e.size();i++){
			while(!stk.empty()&&phi[a[e[stk.top()]]]<phi[a[e[i]]])stk.pop();
			if(!stk.empty()){
				v[e[stk.top()]].push_back({e[i],phi[a[e[stk.top()]]]*phi[a[e[i]]]*d/phi[d]});
			}
			stk.push(i);
		}
		while(!stk.empty())stk.pop();
		reverse(e.begin(),e.end());
		for(int i=0;i<e.size();i++){
			while(!stk.empty()&&phi[a[e[stk.top()]]]<phi[a[e[i]]])stk.pop();
			if(!stk.empty()){
				v[e[i]].push_back({e[stk.top()],phi[a[e[stk.top()]]]*phi[a[e[i]]]*d/phi[d]});
			}
			stk.push(i);
		}
    }
    for(int i=1;i<=Q;i++){
    	cin>>q[i].l>>q[i].r;
    	q[i].id=i;
	}
	sort(q+1,q+Q+1,[&](node x,node y){
		return x.l>y.l;
	});
	int las=n+1;
	for(int k=1;k<=Q;k++){
		for(int i=q[k].l;i<las;i++){
			for(auto it:v[i]){
				sgt.modify(1,1,n,it.x,it.y);
			}
		}
		las=q[k].l;
		res[q[k].id]=sgt.qry(1,1,n,q[k].l,q[k].r);
	}
	for(int i=1;i<=Q;i++){
		cout<<res[i]<<'\n';
	}
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
//    cin>>T;
    init();
    for(int cs=1;cs<=T;cs++){
        solve(cs);
    }
    return 0;
}
posted @ 2025-04-27 20:57  zxh923  阅读(89)  评论(0)    收藏  举报