[BZOJ3512]DZY Loves Math IV(杜教筛)
题面
https://darkbzoj.tk/problem/3512
题解
前置知识
本题不能上手直接反演,这是因为我这么做然后光荣GG了我们发现n不正常地小。
考虑枚举n这一维。设\(S(n,m)={\sum_{j=1}^{m}}{\varphi(nj)}\),那么所求即为\({\sum_{i=1}^{n}}S(i,m)\)。
预处理出s,r数组,如果\(n={\prod_{i=1}^{k}}{p_i}^{\alpha_i}\),那么\(s[n]={\prod_{i=1}^{k}}p_i\),而\(r[n]={\frac{n}{s[n]}}\)。这样,我们就可以从\(\varphi\)函数中提出r,并使得剩下的部分便于操作:(以下r[n]简写成r,s[n]简写成s)
刚才我们拆n为s和r的另一个好处得到了体现:\(\frac{s}{(s,j)}\)和\((s,j)、j\)都互质。
于是可以递归计算了。
递归终止的条件是n=1(用杜教筛求和)或者m=0(返回0)。分析一下复杂度:杜教筛是\(O(m^{\frac{2}{3}})\);计算函数\(S(i,j)\)时,只要\(j<m\),j就一定在\({\lfloor}{\frac{m}{i}}{\rfloor}\)的整除集合中。
再加上计算\(S(i,j)\)的时候需要枚举\(s[i]\)的约数,由于\(i<10^5\),所以\(i\)最多有6个不同的质因子,所以\(s[i]\)最多有64个约数。
总时间复杂度为\(O(m^{\frac{2}{3}}+{\sum_{i=1}^{n}}{\sqrt{\frac{m}{i}}}w(i))\),其中\(w(i)\)指的是\(s[i]\)约数的数量。
视各\(w(i)\)为常数,积分近似可得\(O(m^{\frac{2}{3}}+\overline{w}{\sqrt{nm}})\),其中\({\overline{w}}{\leq}64\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
const ll N = 1e5;
const ll mod = 1e9 + 7;
const ll iv2 = 5e8 + 4;
namespace ModCalc{
inline void Inc(ll &x,ll y){
x += y;if(x >= mod)x -= mod;
}
inline void Dec(ll &x,ll y){
x -= y;if(x < 0)x += mod;
}
inline ll Add(ll x,ll y){
Inc(x,y);return x;
}
inline ll Sub(ll x,ll y){
Dec(x,y);return x;
}
}
using namespace ModCalc;
ll pn;
ll pri[N+5],phi[N+5],sphi[N+5];
bool isp[N+5];
inline void Eular(){
phi[1] = 1;
for(rg ll i = 2;i <= N;i++)isp[i] = 1;
for(rg ll i = 2;i <= N;i++){
if(isp[i])pri[++pn] = i,phi[i] = i - 1;
for(rg ll j = 1;i * pri[j] <= N;j++){
isp[i*pri[j]] = 0;
if(i % pri[j])phi[i*pri[j]] = phi[i] * (pri[j] - 1) % mod;
else{
phi[i*pri[j]] = phi[i] * pri[j] % mod;
break;
}
}
}
for(rg ll i = 1;i <= N;i++)sphi[i] = Add(sphi[i-1],phi[i]);
}
unordered_map<ll,ll>Hash;
inline ll sumphi(ll n){
if(n <= N)return sphi[n];
if(Hash.count(n))return Hash[n];
ll ans = 1ll * (n % mod) * Add(n % mod,1) % mod * iv2 % mod;
ll L,R = 1;
while(R < n){
L = R + 1,R = n / (n / L);
Dec(ans,(R - L + 1) * sumphi(n/L) % mod);
}
return Hash[n] = ans;
}
ll s[N+5],r[N+5];
vector<ll>fac[N+5],g[N+5]; //fac[i]存储i的不同质因子,g[i]存储s[i]的约数
inline void prepro(){
for(rg ll i = 1;i <= pn;i++)
for(rg ll j = pri[i];j <= N;j += pri[i])fac[j].push_back(pri[i]);
for(rg ll i = 1;i <= N;i++){
for(rg ll mask = 0;mask < 1ll << fac[i].size();mask++){
ll cur = 1;
for(rg ll j = 0;j < fac[i].size();j++)
if((bool)(mask&(1ll<<j)))cur *= fac[i][j];
g[i].push_back(cur);
}
s[i] = g[i][g[i].size()-1];
r[i] = i / s[i];
}
}
unordered_map<ll,ll>HashS[N+5];
inline ll S(int n,int m){
if(n == 1)return sumphi(m);
if(!m)return 0;
if(HashS[n].count(m))return HashS[n][m];
ll ans = 0;
for(rg int i = 0;i < g[n].size();i++){
int d = g[n][i];
Inc(ans,phi[s[n]/d] * S(d,m/d) % mod);
}
ans = ans * r[n] % mod;
return HashS[n][m] = ans;
}
int main(){
Eular();
prepro();
ll ans = 0;
ll n,m;
scanf("%lld%lld",&n,&m);
for(rg ll i = 1;i <= n;i++)Inc(ans,S(i,m));
cout << ans << endl;
return 0;
}