ZJOI2014day1居然有两道数学题,再加上WC的经历,看来这个世界不会数学是混不成OI了,于是现在开始学数学吧。。。
膜拜了策神的博客,感触颇多,也学到了很多,做了几道题。
【BZOJ1101】【POI2007】ZAP 用莫比乌斯函数带进去搞搞就好了。
【BZOJ1693】jzptab 方法和上面差不多,莫比乌斯函数带进去然后再代换求和指标,把问题转化为求一个Dirichlet卷积。然后就线性筛做就可以了。
【BZOJ3309】方法同上,最后化出来一个感觉很靠谱的式子,但是要求f和µ的Dirichlet卷积,可以发现当为k个指数相同质数相乘时卷积为(-1)k+1,否则为0。的开始我只会O(nloglogn)的算法,显然TLE,后来一想只要先筛莫比乌斯函数,然后对于每个非0项自乘就可以了,非常简单而且复杂度O(n)
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; long long s[10000010],prime[10000000],pd[10000010],len,n,m; void makeit() { long long n=10000000; memset(s,0x00,sizeof s); memset(pd,0x00,sizeof pd); for (long long i=2;i<=n;i++) { if (!pd[i]) { len++; prime[len]=i; s[i]=1; } for (long long j=1;j<=len;j++) { if (prime[j]*i>n) break; pd[prime[j]*i]=1; if (i%prime[j]==0) { s[i*prime[j]]=0; break; } else s[i*prime[j]]=-s[i]; } } for (long long i=2;i<=int(sqrt(n));i++) if (s[i]!=0) for (long long j=i;j<=n;j=j*i) s[j]=s[i]; for (long long i=2;i<=n;i++) s[i]+=s[i-1]; } int main() { int t; makeit(); scanf("%d",&t); for (;t;t--) { scanf("%lld%lld",&n,&m); if (n>m) swap(n,m); long long tot=0,next; for (long long i=1;i<=n;i=next+1) { next=min(n/(n/i),m/(m/i)); tot+=(s[next]-s[i-1])*(m/i)*(n/i); } printf("%lld\n",tot); } return 0; }