优美函数 题解

题意简述

给你函数 f

f(x,y,u)={uy,x=1u,1<xy, gcd(x,y)=1xy,x1, gcd(x,y)=x0,otherwise.

对于一个长度为 n 的序列 a,定义函数 g

g(l,r,u)=i=1106j=lrf(i,aj,u)

给你 q 个询问,告诉你 (l,u),求 maxr=lng(l,r,u),以及对应的 r,多个最值输出 r 较小的。

n,q5×1051ai1061u1.8×107

题目分析

显然要先观察 f,我们把 i=1106f(i,aj,u) 的代码写出来:

lint res = 0;
for (int i = 1; i <= 1000000; ++i) {
if (i == 1) res += u - a[j];
else if (i <= a[j] && gcd(i, a[j]) == 1) res += u;
else if (gcd(i, a[j]) == i) res += -i * a[j];
}

显然要把 i=1 提出来,然后后面两个 if 是不交的,可以分别考虑。发现此时 i 的上界可以下调至 ajgcd(i,aj)=i 等价于 iaj。再把不变的东西提出来,可以得到如下代码:

lint res = u - a[j];
lint cnt = 0, sum = 0;
for (int i = 2; i <= a[j]; ++i) {
if (gcd(i, a[j]) == 1) ++cnt;
if (a[j] % i == 0) sum += i;
}
res += cnt * u, res -= sum;

我们惊奇地发现,uaj 满足我们 for 里面两个 if 的条件,可以放回去:

lint cnt = 0, sum = 0;
for (int i = 1; i <= a[j]; ++i) {
if (gcd(i, a[j]) == 1) ++cnt;
if (a[j] % i == 0) sum += i;
}
lint res = cnt * u - sum;

这时候,cntsum 就有意义了,分别表示:「1aj 中和 aj 互质的数的个数」、「aj 的所有约数之和」,也就是 φ(aj)σ(aj),这两个都可以线性筛地搞。

可是我不会

考场上忘了,只好现推一遍。其实以前根本不知道啥是 σ,但是实力地推出式子来了!我们只用考虑 imodpj0imodpj=0 两种情况。

  1. φ(x)

    1. imodpj0
      经典积性函数曾说:如果你给我 ab,我能告诉你,φ(ab)=φ(a)φ(b)。所以 φ(ipj)=φ(i)φ(pj)
    2. imodpj=0
      我们记 i=pjtpkipktk。考虑欧拉函数计算式 φ(x)=xpjxpj1pj,就有 φ(i)=φ(ipjt)pjtpj1pj。而 ipjtpjt+1,所以:

     φ(ipj)=φ(ipjtpjt+1)=φ(ipjt)φ(pjt+1)=φ(i)pjtpjpj1(pjt+1ptt)=φ(i)pjtpjpj1(pj1)pjt=φ(i)pj

  2. σ(x)
    考虑 x=pkxpktk,那么 σ(x)=sum{pktktktk},由于 tk 之间互不影响,考虑乘法原理,σ(x)=(1+pk++pktk),这样一定能凑出所有 x 的因数。

    1. imodpj0
      σ(ipj)=σ(i)(1+pj)=σ(i)σ(pj)这里没有一步到位的原因是,我之前不知道 σ,也就没想它是不是积性函数了。
    2. imodpj=0
      同样设 i 中有 pjt,那么 σ(ipj)=σ(ipjt)(1+pj++pjt+1),这很难受,考虑变换一下 σ(ipjt)(1+pj++pjt+1)=σ(i)+σ(ipjt)pjt+1。接下来,我们只需要对一个 x 维护 c(x) 表示 pt,其中 px 的最小质因数,t 是幂次。这个很好维护,当 imodpj0c(ipj)=pj;否则,c(ipj)=c(i)pj。如此,σ(ipj)=σ(i)+σ(ic(i))c(i)pj

对于一次询问,求的式子可以简化成:

maxr=ln{i=lrφ(ai)u+σ(ai)}

对于一个 i 来说,φ(ai)σ(ai) 都是定值,我们可以把它们分别做个前缀和。由于很像一次函数,我们将这两个前缀和记作 K,B

 maxr=ln{KrKl1u+BrBl1}=maxr=ln{Kru+Br}Kl1uBl1

一次函数最值,且 K 有单调性,我们考虑凸包上二分。我们考虑把查询离线到 l 上,从右往左扫,维护一个下凸包(一次函数的最值),查询最值就去二分出 x 在凸包哪条直线上。

时间复杂度:Θ(V+n+qlogn)

代码

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int N = 500010, V = 1000010;
using lint = long long;
int n, q, val[N];
int phi[V], prime[V], pcnt, cj[V];
bool nprime[V];
lint subsum[V], K[N], B[N];
vector<pair<int, int>> qry[N];
lint mx[N];
int mxR[N];
int stack[N], top;
inline bool cmptail(int a, int b, int c) {
return (__int128_t)(B[c] - B[a]) * (K[a] - K[b]) > (__int128_t)(B[b] - B[a]) * (K[a] - K[c]);
}
inline void insert(int idx) {
while (top - 1 >= 1 && cmptail(stack[top - 1], stack[top], idx)) --top;
stack[++top] = idx;
}
inline int query(int x) {
int l = 1, r = top - 1, res = stack[top];
while (l <= r) {
int mid = (l + r) >> 1;
if (1ll * x * (K[stack[mid]] - K[stack[mid + 1]]) >= B[stack[mid + 1]] - B[stack[mid]])
res = stack[mid], r = mid - 1;
else
l = mid + 1;
}
return res;
}
signed main() {
#ifndef XuYueming
freopen("function.in", "r", stdin);
freopen("function.out", "w", stdout);
#endif
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; ++i)
scanf("%d", &val[i]);
phi[1] = 1, subsum[1] = 1;
for (int i = 2; i <= 1000000; ++i) {
if (!nprime[i]) prime[++pcnt] = i, phi[i] = i - 1, subsum[i] = 1 + i, cj[i] = i;
for (int j = 1; j <= pcnt && i * prime[j] <= 1000000; ++j) {
nprime[i * prime[j]] = true;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
subsum[i * prime[j]] = subsum[i] + subsum[i / cj[i]] * cj[i] * prime[j];
cj[i * prime[j]] = cj[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * phi[prime[j]];
subsum[i * prime[j]] = subsum[i] * subsum[prime[j]];
cj[i * prime[j]] = prime[j];
}
}
for (int i = 1; i <= n; ++i) {
K[i] = phi[val[i]];
B[i] = -1ll * subsum[val[i]] * val[i];
K[i] += K[i - 1];
B[i] += B[i - 1];
}
for (int i = 1, u, l; i <= q; ++i) {
scanf("%d%d", &u, &l);
qry[l].emplace_back(u, i);
}
for (int i = n; i >= 1; --i) {
insert(i);
for (auto [x, idx]: qry[i]) {
int ps = query(x);
mx[idx] = (1ll * x * K[ps] + B[ps]) - (1ll * x * K[i - 1] + B[i - 1]);
mxR[idx] = ps;
}
}
for (int i = 1; i <= q; ++i)
printf("%lld %d\n", mx[i], mxR[i]);
return 0;
}
posted @   XuYueming  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示