ICPC 2018 南京网赛 Easy Math 递归式+杜教筛

ICPC 2018 南京网赛 Easy Math

标签

  • 递归式
  • 杜教筛

前言

  • 做了这题,感觉自己又学到了好多东西~
  • 我的csdn和博客园是同步的,欢迎来访danzh-博客园~

简明题意

\[\sum_{i=1}^{m}\mu{(in)} \]

  • \(m<=2e9,n<=1e12\)

思路

  • 推式子吧~
  • 首先莫比乌斯函数,一旦含有平方因子,他的值就是-1.所以我们可以先特判一下n含不含平方因子,含的话,答案就是0。
  • 然后我们看看n不含平方因子的情况。既然n没有平方因子,那么显然n是可以分解成\(p_1p_2...p_n\)的。我们任取其中一个质数p。然后把原式写成:

\[\sum_{i=1}^{m}\mu{(i*p*\frac{n}{p})} \]

  • 想一想鸡性函数性质(此处是积不是鸡,但是鸡太美了所以我就对鸡和积不加区分好了2333),鸡性函数\(g(ab)\),如果ab互质,则有\(g(ab)=g(a)g(b)\),所以我们回到原来的式子,把p提出来,是不是就成了

\[\sum_{i=1}^{m}\mu{(i*p*\frac{n}{p})}=\sum_{i=1}^{m}\mu{(i*\frac{n}{p})}\mu(p) \]

  • 显然不是的,因为那个鸡性函数性质,是需要互质的。而p和i*n/p不一定互质鸭!但是我们先不管这个,待会再考虑这个。假设他俩互质了,一个质数的莫比乌斯函数值一定是-1,我们直接把-1提前,所以原式:

\[-\sum_{i=1}^{m}\mu{(i*\frac{n}{p})} \]

与索引无关的量可以提到和式前面(索引是指上式中的i)

  • 然后我们再回头考虑之前的不互质的情况。p和\(i*\frac{n}{p}\)不互质,而p与n/p互质,可以推出p|i。(这一步很显然,可以自己推一下)。也就是说,对于原式,上面的式子多减去了不互质的情况,而且还少加上了不互质的情况。对于多减去的部分,我们直接加回去就好了。但是少加上的部分呢?少加上的部分是少加上了\(\sum\limits_{i=1}^{m}\mu{(i*p*\frac{n}{p})}[p|i]\),这样的话是不是发现\(\mu\)又有平方因子了呢,所以少加上的值我们不用管,因为他就是0.我们只用关心多减去的部分,加上就好了。
  • 我们把多减去的加回去,显然原式就是:

\[-\sum_{i=1}^{m}\mu{(i*\frac{n}{p})}+\sum_{i=1}^{m}\mu{(i*\frac{n}{p})}[p|i] \]

  • 然后关注后面的那个式子,看到后面的条件\([p|i]\),是不是立马想到更换枚举上限了?所以原式就成了:

\[-\sum_{i=1}^{m}\mu{(i*\frac{n}{p})}+\sum_{i=1}^{\frac mp}\mu{(ip*\frac{n}{p})}=-\sum_{i=1}^{m}\mu{(i*\frac{n}{p})}+\sum_{i=1}^{\frac mp}\mu{(in)} \]

  • 我们另\(S(m,n)=\sum\limits_{i=1}^{m}\mu(in)\),于是,我们终于得到了想要的递归式:

\[S(m,n)=-S(m,\frac np)+S(\frac mp,n) \]

  • 这个二元组的边界条件,就是S(m,1)和S(0,n)。然而mn太大,所以边界直接杜教筛!

注意事项

  • 计算n是否含平方因子,这个时候又prime[i[*prime[i],注意别溢出!

总结

  • 一个数没有平方因子等价于\(n=p_1p_2...p_n\)
  • 我们在计算鸡性函数是,如果计算的是\(f(i*n)\),也就是自变量中含有常数,我们可以尝试把这个常数分解成\(p*\frac np\),从而可以利用鸡性函数性质,从而进一步转化为递归式
  • 与索引无关的量可以提到和式前面
  • \(ab|c\),如果a与c互质,那么\(ab|c \iff b|c\)
  • 对于一个和式,如果索引必须是某个数的倍数,那么可以直接更换上限,然后扩大索引。比如\(\sum\limits_{i=1}^{n}[p|i]\),他等价于\(\sum\limits_{i=1}^{\frac np}1\)(其中i缩小到了原来的p倍,需要乘上)
  • 对于一个二元递归式,边界条件应该是每一元都到边界

AC代码

#include<cstdio>
#include<unordered_map>
using namespace std;

const int maxn = 1e7 + 10;

long long n, m;

int prime[maxn], min_p[maxn], mu[maxn], pre_mu[maxn];
bool no_prime[maxn];
int shai(int n)
{
	int cnt = 0;
	no_prime[1] = mu[1] = 1;

	for (int i = 2; i <= n; i++)
	{
		if (!no_prime[i])
			prime[++cnt] = i, mu[i] = -1, min_p[i] = i;

		for (int j = 1; j <= cnt && i * prime[j] <= n; j++)
		{
			no_prime[prime[j] * i] = 1;
			mu[prime[j] * i] = i % prime[j] == 0 ? 0 : -mu[i];
			min_p[prime[j] * i] = prime[j];
			if (i % prime[j] == 0) break;
		}
	}

	for (int i = 1; i <= n; i++)
		pre_mu[i] = pre_mu[i - 1] + mu[i];

	return cnt;
}

unordered_map<int, int> rec_mu;
int cal(int n)//n的莫比乌斯函数前缀和
{
	if (n <= maxn - 10) return pre_mu[n];
	if (rec_mu[n]) return rec_mu[n];

	int l = 2, r, ans = 1;
	while (l <= n)
	{
		r = n / (n / l);
		ans -= (r - l + 1) * cal(n / l);
		l = r + 1;
	}

	return rec_mu[n] = ans;
}

long long S(long long m, long long n)
{

	if (m == 0) return 0;
	if (n == 1) return cal(m);


	for (int i = 1; 1ll * prime[i] * prime[i] <= n; i++)
	{
		if (n % prime[i] == 0)
			return -S(m, n / prime[i]) + S(m / prime[i], n);
	}
	return -S(m, n / n) + S(m / n, n);
}

void solve()
{
	int cnt = shai(maxn - 10);

	scanf("%lld%lld", &m, &n);

	for (int i = 1; 1ll * prime[i] * prime[i] <= n; i++)
		if (n % (1ll * prime[i] * prime[i]) == 0)
		{
			printf("0\n");
			return;
		}

	printf("%lld\n", S(m, n));
}

int main()
{
	freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}
posted @ 2019-08-23 10:55  danzh  阅读(196)  评论(0编辑  收藏  举报