2018ACM/ICPC徐州站网络赛D Easy Math(杜教筛)

题目链接

题意是给出莫比乌斯函数和n、m,求\sum_{i=1}^{m}\mu \left ( i*n \right )

2018ACM/ICPC徐州站网络赛D Easy Math(杜教筛)_第1张图片

今天看了很久tls的博客,才算对积性函数和杜教筛稍微有了一点了解。链接:点击此处查看原文。

首先,这道题的n和m的范围都很大,所以线性的做法肯定是解决不了问题的。其次,杜教筛有一道求莫比乌斯函数前缀和的模板题(可惜此前我并没有学过杜教筛...据说预处理n^{\frac{2}{3}}个值的前缀和的情况下,可以在O(n^{\frac{2}{3}})的时间复杂度下求出到n的前缀和...),因此很容易就会往杜教筛上联想,所以需要想办法将问题转化为求莫比乌斯函数的前缀和。

首先,当n含有平方因子时,答案为0;
否则,因为莫比乌斯函数为积性函数,若i与n的任意一个因子d互质,则有\mu \left ( i*\frac{n}{d}*d \right )=-\mu \left ( i*\frac{n}{d} \right ),则可得\sum_{i=1}^{m}\mu \left ( i*\frac{n}{d}*d \right )=-\sum_{i=1}^{m}\mu \left ( i*\frac{n}{d} \right )+\sum_{i=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\mu \left ( i*n \right ),后面加上的那部分代表d的所有在m以内的倍数乘以n/d的莫比乌斯函数的和, \sum_{i=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\mu \left ( i*d*\frac{n}{d} \right )=\sum_{i=1}^{\left \lfloor \frac{m}{d} \right \rfloor}\mu \left ( i*n \right ) 。为什么要加上它呢?因为当i与d不互质时,i和n/d可能互质,也就是说可能出现\mu \left ( i*n \right )=0但是\mu \left ( i*\frac{n}{d} \right )!=0的情况,如果只含有前面那部分的话相当于多减掉了这部分的\mu \left ( i*\frac{n}{d} \right ),因此需要加上这部分。当然,加上的这部分中肯定也包括了两者都为0的情况,但是都为0对结果没有影响,算上也没关系,方便计算。

由上面的式子可以看出,可以通过递归计算,当出现m=0的情况时,返回0;当出现n=1的情况时,返回前缀和(通过杜教筛计算)。

代码如下:

#include
using namespace std;
#define ll long long
#define For(i,a,b) for(int i=a;i<=b;i++)
#define INF 0x3f3f3f3f
#define db double
#define ldb long double
#define m_p make_pair
#define p_b push_back
#define fbo friend bool operator <
const int N = 1000010;
const int mod=1e9+7;
bool notprime[N];
ll prime[N/10],cnt,mu[N];
vector fac;
inline bool Prime(ll x){
	notprime[1]=mu[1]=1;
	For(i,2,N-1){
		if(!notprime[i]) prime[cnt++]=i,mu[i]=-1;
		for(int j=0;j1) fac.p_b(x);
	return true;
}
unordered_map S;
inline ll Sum(ll x){
  if (x>m>>n;
	if(Prime(n)){
		printf("%lld\n",cal(m,n));
	}
	else printf("0\n");
	return 0;
}

 

你可能感兴趣的:(数论的学习)