bzoj2154 Crash的数字表格

       首先得到朴素递推式,然后运用莫比乌斯反演得到:bzoj2154 Crash的数字表格_第1张图片

       然后可以发现后面的值之和N/d和M/d有关,只有O(N^0.5)种;而后面的值同样可以分段O(N^0.5)解决,因此时间复杂度O(N)。

AC代码如下:

#include<iostream>
#include<cstdio>
#define ll long long
#define mod 20101009
#define N 10000005
using namespace std;

int n,m,cnt,mu[N],c[N],sum[N]; bool vis[N];
void pfs(){
	int i,j; mu[1]=1;
	for (i=2; i<=m; i++){
		if (!vis[i]){ c[++cnt]=i; mu[i]=-1; }
		for (j=1; j<=cnt && i*c[j]<=m; j++){
			vis[i*c[j]]=1;
			if (i%c[j]) mu[i*c[j]]=-mu[i]; else{
				mu[i*c[j]]=0; break;
			}
		}
	}
	for (i=1; i<=m; i++){
		sum[i]=sum[i-1]+i; if (sum[i]>=mod) sum[i]-=mod;
		mu[i]=((ll)i*i*mu[i]+mu[i-1])%mod;
	}
}
int solve(int x,int y){
	int i,j,ans=0;
	for (i=1; i<=x; i=j+1){
		j=min(x/(x/i),y/(y/i));
		ans+=(ll)sum[x/i]*sum[y/i]%mod*(mu[j]-mu[i-1]+mod)%mod;
		if (ans>=mod) ans-=mod;
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m); int i,j,ans=0;
	if (n>m) swap(n,m); pfs();
	for (i=1; i<=n; i=j+1){
		j=min(n/(n/i),m/(m/i));
		ans+=(ll)solve(n/i,m/i)*(sum[j]-sum[i-1]+mod)%mod;
		if (ans>=mod) ans-=mod;
	}
	printf("%d\n",ans);
	return 0;
}


by lych

2016.3.16       

你可能感兴趣的:(数论,莫比乌斯反演,线性筛)