【莫比乌斯反演】BZOJ1101 [POI2007]zap
2015-06-24 00:41
323 查看
Description
回答T组询问,有多少组gcd(x,y)=d,x<=a, y<=b。T, a, b<=4e5。Solution
显然对于gcd=d的,应该把a/d b/d,然后转为gcd=1计算计算用莫比乌斯反演相信大家都会
关键是有T组询问n^2会T
于是有这样一个优化可以做到每次sqrt(n)
每一次是ret+=mu[i]*(n/i)*(m/i)
可是除法向下取整所以会导致很多i的(n/i)*(m/i)一样
具体来说,向下取整得到的结果一定是约数所以对于(n/i)最多2sqrt(n)种
那么(n/i)*(m/i)放一起也就4sqrt(n)种
这个序列一定是不上升的,所以考虑对所有的(n/i)*(m/i)视为一块相同的一起算
那么肯定要记录下mu[i]的前缀和
如何快速得到每一块的l和r?
每一块的r肯定要么n%i==0要么m%i==0
于是用pos=min(n/(n/i),m/(m/i)) 定位
当然pos+1就是下一块的l了
Code
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=5e4+5; int flag[maxn],prime[maxn],cnt; int mu[maxn],sum[maxn]; int getmu(){ mu[1]=1; for(int i=2;i<maxn;i++){ if(!flag[i]){ prime[++cnt]=i; mu[i]=-1; } for(int j=1;i*prime[j]<maxn&&j<=cnt;j++){ flag[i*prime[j]]=1; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; } mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<maxn;i++) sum[i]=sum[i-1]+mu[i]; } int cal(int n,int m){ int ret=0,pos; if(n>m) swap(n,m); for(int i=1;i<=n;i=pos+1){ pos=min(n/(n/i),m/(m/i)); ret+=(sum[pos]-sum[i-1])*(n/i)*(m/i); } return ret; } int main(){ int T,a,b,d; scanf("%d",&T); getmu(); while(T--){ scanf("%d%d%d",&a,&b,&d); a/=d,b/=d; printf("%d\n",cal(a,b)); } return 0; }
相关文章推荐
- 分布式系统设计理念
- leetcode 10 -- Regular Expression Matching
- 获取文件夹下得所有文件,并按文件夹先,文件后的顺序排
- LeetCode——Happy Number
- IOS 开发注意的问题
- volley源码解析(七)--最终目的之Response<T>
- 看锋利的Jquery发现有感
- 轮廓检测(1)
- 触摸事件
- OBJ文件格式详解
- android调试时apk可运行,导出签名的apk后闪退
- 笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-09 事务和并发
- synchronized使用方法
- 隐藏状态栏、设置全屏、取消全屏
- Java中Synchronized的用法
- 隐藏状态栏、设置全屏、取消全屏 2015-06-24 00:25 7人阅读 评论(0) 收藏
- 内存管理
- hadoop图像处理接口hipi
- 怪异问题:qwidget: must construct a qapplication before a qpaintdevice
- hadoop的文件操作