虽然考试的时候交了暴力(正解在手上却欧拉函数莫比乌斯函数傻傻分不清)
稍微交换一下枚举顺序
使用莫比乌斯函数:
再次交换枚举顺序
不妨令 有
稍作转换:
再一次交换枚举顺序
发现整数分块可以再一次On的预处理后得到的优秀时间复杂度
但是这是远远不够的
不妨设
打表找出规律:
给出证明:
当有
和
会被枚举两次他们必然会两两抵消,或者就是0
所以存在的时间复杂度的预处理和
的查询算法
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int INT;
#define int long long
const int mod=998244353;
const int N=1e7+100;
int sum[N]={0},mu[N]={0},is_prime[N]={0},mark[N];
int cnt=0;
void pre_mul(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!mark[i]){
cnt++;
is_prime[cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&is_prime[j]*i<N;j++){
mark[is_prime[j]*i]=1;
if(i%is_prime[j]==0){
mu[is_prime[j]*i]=0;
break;
}
mu[is_prime[j]*i]=-mu[i];
}
}
sum[0]=0;
for(int i=1;i<N;i++){
sum[i]=mu[i]+sum[i-1];
}
}
inline int Getsum(int x){
int Id=sqrt(x);
return sum[Id];
}
void Solve(){
int n,m;
cin>>n>>m;
if(n>m)
swap(n,m);
int ans=0;
int last;
for(int i=1;i<=n;i=last+1){
last=min(n/(n/i),m/(m/i));
ans=(ans+((n/i)%mod)*((m/i)%mod)%mod*((Getsum(last)-Getsum(i-1))%mod)%mod+mod)%mod;
}
cout<<ans;
}
INT main(){
pre_mul();
Solve();
return 0;
}
但是对于这一类题有一种更好的翻译:
当且仅当
不是x的约数
于是考虑容斥:
就完了
而且整数分块有4的常数!!!
所以对一道题的翻译很重要啊。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int INT;
#define int long long
const int mod=998244353;
const int N=4e6+100;
int sum[N]={0},mu[N]={0},is_prime[N]={0},mark[N];
int cnt=0;
void pre_mul(){
mu[1]=1;
for(int i=2;i<N;i++){
if(!mark[i]){
cnt++;
is_prime[cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&is_prime[j]*i<N;j++){
mark[is_prime[j]*i]=1;
if(i%is_prime[j]==0){
mu[is_prime[j]*i]=0;
break;
}
mu[is_prime[j]*i]=-mu[i];
}
}
sum[0]=0;
for(int i=1;i<N;i++){
sum[i]=mu[i]+sum[i-1];
}
}
inline int Getsum(int x){
int Id=sqrt(x);
return sum[Id];
}
void Solve(){
int n,m;
cin>>n>>m;
if(n>m)
swap(n,m);
int ans=0;
int last;
for(int i=1;i;i++){
int t=i*i;
ans=ans+mu[i]*((n/t)%mod)%mod*((m/t)%mod)%mod;
ans=(ans+mod)%mod;
if(t>n)break;
}
cout<<ans<<'\n';
// cout<<(((n%mod)*(m%mod)-ans)%mod+mod)%mod;
}
INT main(){
pre_mul();
Solve();
return 0;
}