今天做的一个很有成就感的题目,虽然经过我一个上午的痛苦挣扎,但是我觉得这个时间还是花的挺有意义的。

题目的意思是给你a和b两个数(范围是10^7),从1-a选一个数x,从1-b中间选择一个数,问你能选出来gcd(a,b)=素数 的方案数有多少?

这是一类典型的gcd统计问题,也是十分有代表性的一个题目。

首先看到这个题目的时候我也不知道如何入手呢,任何的想法都逃不过T的阴影。

后来去网上看了各路神牛的题解我才稍稍明白了过来呢。

这个题目主要用到的只是就是莫比乌斯反演(Mobius)。

其本质是容斥原理。

如果我们假设d是一个质数,那么题目要我们求的就是 Sigama( mobi[j]*(n/(d*j))*(m/(d*j)) );

这里也就把容斥原理体现得淋漓尽致了,什么意思呢?

我们可以这样理解,我们枚举所取的两个数的最小公倍数的情况,如果当前我们枚举的数为x,那么在它在第一个范围里面有a/x种选择;它在第二个范围里面有b/x种选择,显然对于当前,我们总共的选择数就有(a/x)*(b/x),然而,我们到底加上这个数还是减去这个数呢?首先如果x是一个质数的话,我们应该加上去,但是如果x是恰好由两个不同质数组成的话呢,我们就要减去这个数(显然一个质数的情况已经把两个质数的种类数加进去了,所以这次要把多余的减出来),这里我们就可以得到一个规律,如果把x分解成质数的连乘形式中不含有任何相同的项,那么如果质数的个数为奇数的话,应该加上这个情况数,如果为偶数的话就应该减去这个数。

讲到这里,你也许会认为这个题目可以引刃而解了,但是你看看数据你就会知道,,如果赤裸裸的算的话,时间复杂度是(n*log(n)),果断是不能承受的。(本题连(O(n))的时间复杂度都难以承受哦)。

于是我们不得不再想优化的办法呢。

刚刚说的是枚举所取得的gcd(质数),不如我们换一个思路想想,其实我们可以直接枚举(j*d),也就是质数的若干倍。

同上面容斥原理的分析法,我们根据(j*d)中间分解成质数连乘后,可以很迅速的得出前面的容斥系数(也就是要加上多少或者减去多少的那个数)。

由于j*d里面可以有很多个质数因子组成(设为k个),如果k为偶数,那么d可以是其中任何一个(即d可能有k种取法),这是剩下的因子的个数是奇数个,我们应该加上这个数,所以是正1,由于有k种取法,这是的容斥系数应该是正k;同理当k为奇数时,容斥系数为负k。

但是,如果j*d里面有恰好一个平方因子呢?这是我们的d只可能取那个平方因子的那个数(想想为什么?不然就为o啦),所以这里的容斥系数质可能为1或者-1哦。

对于其他的(多对平方因子),直接等于0。

有了这个想法,我们可以先预处理每个数对应的那个容斥系数,这样就加速啦。

优化到这里,我们离AC又进了一步。但是用这个算法一步步枚举j*d,然后求和,时间复杂度还是有O(n) ,无法通过。

我们要继续想点别的办法。

于是我们又回到求和的那个式子——Sigama( mobi[j]*(n/(d*j))*(m/(d*j)) );

我们可以看到,对于某些d*j,他们所对应的(n/(d*j))*(m/(d*j))的值是不变的,什么意思呢?

举个例子:8/3=8/4=2(向下整除),8/5=8/6=8/7=8/8=1;

于是我们又想,对于那种很大的n和m,他们这种情况会更加明显。

于是我们可以通过对mobi函数求一个前缀和,存入S数组,进行分块处理。

于是我们可以把对应值相同的所有d*j一起处理,由于对于一个被除数,它所对应的商不会太多,这样分块处理后就可以把时间复杂度减低到sqrt级别了。

这样的话就可以顺利的过了这个题目啦。

注:SPOJ卡常数已经到了无节操的境界,所以任何可以降低常数的方法都应该用上的。

下面上代码(部分参考):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdio>
#define ll long long
#define maxn 10000001
using namespace std; char cnt1[maxn],cnt2[maxn];//把字符当做整形,因为longlong的范围最多都只有64位,足够,而且这里运算快得多,有了这个优化时间直接减少至少15s。
int s[maxn]; void getprim()
{
int k;
s[1]=0;
for (int i=2; i<maxn; i++)
{
if (cnt1[i]==0)
{
for (int j=i; j<maxn; j+=i) cnt1[j]++;
        //不用朴素的筛选素数的方法,直接用平方和立方的情况筛选,省时多了。
if (i<3165)
{
k=i*i;
for (int j=k; j<maxn; j+=k) cnt2[j]++;
}
if (i<217)
{
k=i*i*i;
for (int j=k; j<maxn; j+=k) cnt2[j]++;
}//这里只要考虑平方和立方,为什么?因为含有的i^2的数目等于2和大于2的容斥系数都是0,我们只要知道那个系数大于1就可以了,不必要知道具体是多少。这里减去了好多白花花的时间。
}
if (cnt2[i]==0) k=(cnt1[i]&1)?cnt1[i]:-cnt1[i];
else if (cnt2[i]==1) k=(cnt1[i]&1)?-1:1;
else k=0;//k为第i项的容斥系数值,但是我们只需要前缀和。
s[i]=k+s[i-1];
}
} int main()
{
getprim();
int n,m,cas,next,d1,d2;
llans;
scanf("%d",&cas);
while (cas--)
{
ans=0;
scanf("%d%d",&n,&m);
for (lli=2; i<=n && i<=m;)
{
d1=n/i,d2=m/i;
next=n/d1<m/d2?n/d1:m/d2;
ans+=(ll)(s[next]-s[i-1])*d1*d2;
i=next+1;//分块,跳到下一块的起点。
}
printf("%lld\n",ans);
} return 0;
}

SPOJ PGCD的更多相关文章

  1. SPOJ - PGCD Primes in GCD Table(莫比乌斯反演)

    http://www.spoj.com/problems/PGCD/en/ 题意: 给出a,b区间,求该区间内满足gcd(x,y)=质数的个数. 思路: 设f(n)为 gcd(x,y)=p的个数,那么 ...

  2. SPOJ PGCD (mobius反演 + 分块)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题意 :求满足gcd(i , j)是素数(1 &l ...

  3. SPOJ PGCD 4491. Primes in GCD Table && BZOJ 2820 YY的GCD (莫比乌斯反演)

    4491. Primes in GCD Table Problem code: PGCD Johnny has created a table which encodes the results of ...

  4. SPOJ PGCD(莫比乌斯反演)

    传送门:Primes in GCD Table 题意:给定两个数和,其中,,求为质数的有多少对?其中和的范围是. 分析:这题不能枚举质数来进行莫比乌斯反演,得预处理出∑υ(n/p)(n%p==0). ...

  5. bzoj 2820 / SPOJ PGCD 莫比乌斯反演

    那啥bzoj2818也是一样的,突然想起来好像拿来当周赛的练习题过,用欧拉函数写掉的. 求$(i,j)=prime$对数 \begin{eqnarray*}\sum_{i=1}^{n}\sum_{j= ...

  6. * SPOJ PGCD Primes in GCD Table (需要自己推线性筛函数,好题)

    题目大意: 给定n,m,求有多少组(a,b) 0<a<=n , 0<b<=m , 使得gcd(a,b)= p , p是一个素数 这里本来利用枚举一个个素数,然后利用莫比乌斯反演 ...

  7. 【HDU4947】GCD Array (莫比乌斯反演+树状数组)

    BUPT2017 wintertraining(15) #5H HDU- 4947 题意 有一个长度为l的数组,现在有m个操作,第1种为1 n d v,给下标x 满足gcd(x,n)=d的\(a_x\ ...

  8. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  9. SPOJ DQUERY D-query(主席树)

    题目 Source http://www.spoj.com/problems/DQUERY/en/ Description Given a sequence of n numbers a1, a2, ...

随机推荐

  1. 2017-2018-1 20155306 20155315 《信息安全技术》实验二、Windows口令破解

    在网络界,攻击事件发生的频率越来越高,其中相当多的都是由于网站密码泄露的缘故,或是人为因素导致,或是口令遭到破解,所以从某种角度而言,密码的安全问题不仅仅是技术上的问题,更主要的是人的安全意识问题. ...

  2. centos7安装cacti

    参考博客地址:https://blog.csdn.net/kenn_lee/article/details/80565385 Cacti是一套基于PHP,MySQL,SNMP及RRDTool开发的网络 ...

  3. DIRECT3D状态详解

    Microsoft® Direct3D®设备是一个状态机.应用程序设置光照.渲染和变换模块的状态,然后在渲染时传递数据给它们. 本节描述图形流水线用到的所有不同类型的状态. 渲染状态 取样器状态 纹理 ...

  4. day6 RHCE

    17.创建一个脚本 在server0上创建一个名为/root/foo.sh的脚本,让其提供下列特性: 当运行/root/foo.sh redhat,输出fedora 当运行/root/foo.sh f ...

  5. 【LG3835】可持久化平衡树

    [LG3835]可持久化平衡树 题面 洛谷 解法一 参考文章 rope大法好 \(rope\)基本操作: #include<ext/rope> using namespace __gnu_ ...

  6. dotnet core在Task中使用依赖注入的Service/EFContext

    C#:在Task中使用依赖注入的Service/EFContext dotnet core时代,依赖注入基本已经成为标配了,这就不多说了. 前几天在做某个功能的时候遇到在Task中使用EF DbCon ...

  7. Spring学习(八)-----Spring注入值到集合类型的例子

    下面例子向您展示Spring如何注入值到集合类型(List, Set, Map, and Properties). 支持4个主要的集合类型: List – <list/> Set – &l ...

  8. css布局笔记(一)

    布局方式 一列布局 通常固定宽高,用margin:0 auto:居中显示 两列布局 说起两列布局,最常见的就是使用float来实现.float浮动布局的缺点是浮动后会造成文本环绕等效果,以及需要及时清 ...

  9. 优化 VR 动作类游戏《Space Pirate Trainer*》以便在英特尔® 集成显卡上实现卓越的表现

    Space Pirate Trainer* 是一款面向 HTC Vive*.Oculus Touch* 和 Windows Mixed Reality* 的原创发行游戏.版本 1.0 于 2017 年 ...

  10. 初次学习asp.net core的心得

    初次学习Asp.Net Core方面的东西,虽然研究的还不是很深,今天主要是学习了一下Asp.Net Core WebAPI项目的使用,发现与Asp.Net WebAPI项目还是有很多不同.不同点包含 ...