虽然题目上写了反演但是我不知道什么是反演……如果你把Sigma调换位置叫做反演的话。
这道题题面非常简单:
设 d(x) 为 x 的约数个数,给定 N、M ,
求
G(N,M)−G(N−1,M)−G(N,M−1)+G(N−1,M−1)
=∑∞i=1∑∞j=1(⌊Ni⌋−⌊N−1i⌋)(⌊Mi⌋−⌊M−1i⌋)[gcd(i,j)==1]
现在我们来考虑一下G的二阶差分的意义。
(⌊Ni⌋−⌊N−1i⌋) 只有当 i|N 的时候才为 1 , (⌊Mi⌋−⌊M−1i⌋) 同理。
即满足 1≤i≤N,1≤j≤M,gcd(i,j)=1,且i|N,j|M 的有序数对 (i,j) 的个数。由于 i、j 分别是 N、M 的约数,因此对于任意两个不同的质因子 p、q ,它们的选择方案是互不影响的。
因此可以考虑 NM 的任一质因子 p ,设 x、y 分别是满足 px|i,py|j 的最大整数。可以得出,质因子 p 在等式左边的选法数为 x+y+1 ,而在等式右边的选法数也是 x+y+1 (因为当i、j中的其中一个含有质因子p时,另一个就不可以含有质因子p)。
因此该等式成立。我们继续对该式进行变换,可以得到
void genPrime(int n){
memset(isprime,true,sizeof isprime);
mu[1]=d[1]=c[1]=1;
for(int i=2;i<=n;++i){
if(isprime[i]){
prime[tot++]=i;
mu[i]=-1;
c[i]=1;
d[i]=2;
}
for(int j=0;jfalse;
if(i%prime[j]==0){
d[i*prime[j]]=d[i]/(c[i]+1)*(c[i]+2);
c[i*prime[j]]=c[i]+1;break;
}
mu[i*prime[j]]=-mu[i];
d[i*prime[j]]=d[i]*d[prime[j]];
c[i*prime[j]]=1;
}
}
}
代码:
#include
#include
#include
using namespace std;
typedef long long ll;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
const int maxn=50001;
int tot,prime[30001],mu[maxn],c[maxn];
ll d[maxn];
bool isprime[maxn];
ll Ans[101][101];
void genPrime(int n){
memset(isprime,true,sizeof isprime);
mu[1]=d[1]=c[1]=1;
for(int i=2;i<=n;++i){
if(isprime[i]){
prime[tot++]=i;
mu[i]=-1;
c[i]=1;
d[i]=2;
}
for(int j=0;jfalse;
if(i%prime[j]==0){
d[i*prime[j]]=d[i]/(c[i]+1)*(c[i]+2);
c[i*prime[j]]=c[i]+1;break;
}
mu[i*prime[j]]=-mu[i];
d[i*prime[j]]=d[i]*d[prime[j]];
c[i*prime[j]]=1;
}
}
for(int i=1;i<=n;++i) mu[i]+=mu[i-1];
for(int i=1;i<=n;++i) d[i]+=d[i-1];
}
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
return x;
}
char a[18];
inline void print(ll x){
a[0]=0;
while(x) a[++a[0]]=x%10,x/=10;
for(;a[0];--a[0])
putchar(a[a[0]]+48);
putchar('\n');
}
int main(){
genPrime(50000);
int t=read();
while(t--){
int n=read(),m=read();
if(n<=100&&m<=100){
if(Ans[n][m]){
print(Ans[n][m]);
continue;
}
}
if(n>m) swap(n,m);
ll ans=0;
for(int i=1,nex;i<=n;i=nex+1){
nex=min(n/(n/i),m/(m/i));
ans+=(mu[nex]-mu[i-1])*d[n/i]*d[m/i];
}
if(n<=100&&m<=100) Ans[n][m]=Ans[m][n]=ans;
print(ans);
}
return 0;
}