Soulist
2019-03-01 21:54:20
题目要我们求一个很毒瘤的东东:
我们可以很套路地去化简这个式子:(
也就是:
一般地,我们把
后面那一坨其实只和
记
所以原来的式子其实就是:
考虑套路:记
所以原来的式子就是:
其实也就是:
接下来我们考虑两个积性函数的卷积:
其中:
简单证明一下:
其实就是:
也就是:
接着我们考虑对于
考虑
不难发现:
所以:
接下来我们证明这个:
不难发现,卷积其实具有交换律。
所以:
即:
完毕
回到原来的式子:
其实就是:
后面那一部分其实就是:
所以我们要求的就是:
考虑记
然后我们不难发现这是一个积性函数。
所以我们要求的就是:
这一部分可以整除分块,而后面的部分,因为
假定存在
那么这两个的卷积就是:
我们把
这个里面最麻烦的是什么呢?是在
是这个:
所以:
故我们可以令
于是我们所求即:
糟糕,是心动的感觉:
换下顺序,再利用一下乘法分配律,这个式子就是:
但是后面这个,我们给它乘上一个
(最后一步是之前证明的:
所以我们后面的这一坨也就是:
于是:
就是:(其中
然后我们把杜教筛的式子套上去,
记
所以:
因为
而前面这一坨:
然而,观察第一个式子,其就是:
然而当
那么
这个东西怎么算?
相信大家其实上过小学奥数
所以原式:
然后后面这个仍然可以整除分块求,而且再利用递归去做。
但是,整除分块的过程注意到:
假设
即:
因为
所以我们要求
可以利用:
可以记
(小学数学)
再做一个减法,所以
所以最后我们得到了一个比较优秀的式子:
利用整除分块,对
毕竟:
所以不难得到递推:
根据实测,大概
写这篇题解算是帮自己同时复习杜教筛和莫比乌斯反演吧
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
int read() {
char cc = getchar(); int cn = 0, flus = 1;
while(cc < '0' || cc > '9') { if( cc == '-' ) flus = -flus; cc = getchar(); }
while(cc >= '0' && cc <= '9') cn = cn * 10 + cc - '0', cc = getchar();
return cn * flus;
}
const int N = 5e6 + 5;
#define inf 9999999
#define g(x) (((( (x % mod) * ((x + 1) % mod) / 2 ) % mod) * ( (x % mod) * ((x + 1) % mod) / 2 % mod)) % mod)
#define g2(x) (( (x % mod) * ((x + 1) % mod) % mod * ((2 * x + 1) % mod) % mod * inv6 % mod) % mod)
int n, phi[N], pr[N], f[N], top, mod, inv6, inv2;
bool isp[N];
map<int, int> map1;
void init() {
phi[1] = f[1] = 1;
for ( int i = 2; i <= n; ++ i ) {
if( !isp[i] ) pr[++top] = i, phi[i] = i - 1;
for ( int j = 1; j <= top; ++ j ) {
if( i * pr[j] > n ) break;
isp[i * pr[j]] = 1;
if( i % pr[j] == 0 ) {
phi[i * pr[j]] = phi[i] * pr[j];
break;
}
phi[i * pr[j]] = phi[i] * phi[pr[j]];
}
f[i] = f[i - 1] + ((1ll * phi[i] * i) % mod * i) % mod; f[i] %= mod;
}
}
int fpow( int x, int k ) {
int base = x, ans = 1;
while( k ) {
if( k & 1 ) ans *= base, ans %= mod;
base *= base, base %= mod;
k >>= 1;
}
return ans;
}
int phi_sum( int x ) {
if( x <= n ) return f[x];
if( map1[x] ) return map1[x];
int sumId = g(x % mod) % mod, ans = 0;
int l, r;
for ( l = 2; l <= x; l = r + 1 ) {
r = ( x / ( x / l ) );
ans += ((1ll * (( g2(r) - g2((l - 1)) + mod ) % mod ) * phi_sum( x / l )) % mod);
ans %= mod;
}
return map1[x] = ( (sumId - ans + mod) % mod );
}
int solve1( int x ) {
int l, r, ans = 0;
for ( l = 1; l <= x; l = r + 1 ) {
r = ( x / ( x / l ) );
int ret = g( x / l ) % mod;
ret = ret * ((phi_sum(r) - phi_sum(l - 1) + mod) % mod), ret %= mod;
ans += ret, ans %= mod;
}
return (ans + mod) % mod;
}
signed main()
{
mod = read();
// inv2 = fpow( 2, mod - 2 );
inv6 = fpow( 6, mod - 2 );
int x = read();
n = 5000000; init();
printf("%lld", solve1(x));
return 0;
}