B.日记和欧拉函数
题意
给定 \(L,R,B\),求 \(\sum_{i=L}\limits^{R}\varphi^{\left(\max_{j=1}^i\varphi(j)-B\right)}(i)\).
思路
注:此文中 \(p\) 均代表质数。
首先,观察到 \(\varphi^k(x)\) 是一个下降很快的函数,\(k\) 不用很大就可以达到不动点 \(1\)。证明如下:
分类讨论。
若 \(x\equiv 0\pmod 2\),则只有奇数与 \(x\) 互质,于是 \(\varphi(x)\le\frac x2\)。
若 \(x\equiv 1\pmod 2\),若 \(i\) 与 \(x\) 互质,则 \(x-i\) 必定也与 \(x\) 互质。则 \(\varphi(x)\) 为偶数。
所以至多 \(2\) 次即可将 \(x\) 降到 \(\frac x2\) 以下,即 \(k\) 的上界为 \(2\left\lceil\log_2(x)\right\rceil\)。
其次,我们观察 \(\max_{j=1}^i\varphi(j)-B\),不妨令 \(m(x)=\max_{j=1}^x\varphi(j)\)。
1.当 \(x\le B\) 时,\(m(x)\le x \le B\)。则此时 \(f(x)=x\)。
2.当 \(x\ge p\ge B+l\)(\(l\) 为常数,约为 \(400\))时,\(m(x)\ge\varphi(p)=p-1\ge B+l-1\)。则此时 \(k\) 太大,可以直接将 \(f(x)\) 看成 \(1\)。
所以我们只需要计算中间 \(B<x<B+l\) 的部分。而这部分数只有 \(l\) 个,预处理即可。
实际上做的时候其实是计算 \([p_1,p_2]\) 这个区间的数。其中 \(p_1\le B\le B+l\le p_2\)。
总复杂度为 \(O(l\sqrt{n}\log(n)+T)\)。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fileio(x,y) freopen(x,"r",stdin),freopen(y,"w",stdout)
#define tup tuple<int,int,int>
#define pii pair<int,int>
#define bit(x) bitset<x>
#define pb emplace_back
#define mt make_tuple
#define mp make_pair
const int mod=998244353;
const int maxn=1e6+10;
const int L=400;
int a[maxn],f[maxn],s[maxn];
int b,p1,p2;
bool isp(int x) { for(int i=2; i<=sqrt(x); i++) if(!(x%i)) return false; return true; }
int phi(int x) { int tar=x; for(int i=2; i<=sqrt(x); i++) if(!(x%i)) { tar-=tar/i; while(!(x%i)) x/=i; } if(x>1) tar-=tar/x; return tar; }
int calc(int x,int maxx) { if(maxx<=0) return x; return calc(phi(x),maxx-1); }
void init()
{
p1=b,p2=b+L;
while(!isp(p1)) p1--;
while(!isp(p2)) p2++;
int maxx=0;
for(int i=p1; i<=p2; i++)
{
maxx=max(maxx,phi(i));
f[i-p1]=calc(i,maxx-b);
s[i-p1]=(i>p1)*s[i-p1-1]+f[i-p1];
// cerr<<"POS "<<i<<' '<<f[i-p1]<<' '<<phi(i)<<'\n';
}
return;
}
int solve(int x)
{
if(x<p1) return x*(x+1)/2;
if(x<=p2) return p1*(p1-1)/2+s[x-p1];
return p1*(p1-1)/2+s[p2-p1]+x-p2;
}
void work()
{
/* Code */
int x,y; cin>>x>>y;
cout<<solve(y)-solve(x-1)<<'\n';
return;
}
signed main()
{
// fileio("euler.in","euler.out");
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t>>b;
init();
while(t--)
work();
// for(int i=1; i<=10; i++) cerr<<solve(i)-solve(i-1)<<' '; cerr<<'\n';
return 0;
} // Texas yyds !!!