[bzoj 2693] jzptab & [bzoj 2154] Crash的数字表格 (莫比乌斯反演)

题目描述

T T T组数据,给出 N N N, M M M,求 ∑ x = 1 N ∑ y = 1 M l i m ( x , y ) \sum_{x=1}^N\sum_{y=1}^M lim(x,y)\newline x=1Ny=1Mlim(x,y)
N , M &lt; = 10000000 T &lt; = 10000 N,M &lt;= 10000000\newline T&lt;= 10000 N,M<=10000000T<=10000

题目分析

直接开始变换,假设N<M
A n s = ∑ x = 1 N ∑ y = 1 M x y ( x , y ) = ∑ T = 1 N 1 T ∑ x = 1 N ∑ y = 1 M x y [ ( x , y ) = = T ] = ∑ T = 1 N 1 T ∑ x = 1 ⌊ N T ⌋ ∑ y = 1 ⌊ M T ⌋ x y T 2 [ ( x , y ) = = 1 ] = ∑ T = 1 N T ∑ x = 1 ⌊ N T ⌋ ∑ y = 1 ⌊ M T ⌋ x y ∑ d ∣ x , d ∣ y μ ( d ) = ∑ d = 1 N μ ( d ) ∑ T = 1 N T ∑ d ∣ x ⌊ N T ⌋ x ∑ d ∣ y ⌊ M T ⌋ y = ∑ d = 1 N μ ( d ) ∑ T = 1 N T d 2 ∑ x = 1 ⌊ ⌊ N T ⌋ d ⌋ x ∑ y = 1 ⌊ ⌊ M T ⌋ d ⌋ y = ∑ d = 1 N μ ( d ) ∑ T = 1 N T d 2 ∑ x = 1 ⌊ N T d ⌋ x ∑ y = 1 ⌊ M T d ⌋ y 此 时 令 k = T d A n s = ∑ k = 1 N ∑ T ∣ k μ ( ⌊ k T ⌋ ) k ⌊ k T ⌋ ∑ x = 1 ⌊ N k ⌋ x ∑ y = 1 ⌊ M k ⌋ y = ∑ k = 1 N k ∑ T ∣ k μ ( T ) T ∑ x = 1 ⌊ N k ⌋ x ∑ y = 1 ⌊ M k ⌋ y Ans=\sum_{x=1}^N\sum_{y=1}^M \frac {xy}{(x,y)}\newline =\sum_{T=1}^N\frac 1T\sum_{x=1}^N\sum_{y=1}^Mxy[(x,y)==T]\newline =\sum_{T=1}^N\frac 1T\sum_{x=1}^{⌊\frac NT⌋}\sum_{y=1}^{⌊\frac MT⌋}xyT^2[(x,y)==1]\newline =\sum_{T=1}^NT\sum_{x=1}^{⌊\frac NT⌋}\sum_{y=1}^{⌊\frac MT⌋}xy\sum_{d|x,d|y}\mu(d)\newline =\sum_{d=1}^N\mu(d)\sum_{T=1}^{N}T\sum_{d|x}^{⌊\frac NT⌋}x\sum_{d|y}^{⌊\frac MT⌋}y\newline =\sum_{d=1}^N\mu(d)\sum_{T=1}^{N}Td^2\sum_{x=1}^{⌊\frac{⌊\frac NT⌋}d⌋}x\sum_{y=1}^{⌊\frac{⌊\frac MT⌋}d⌋}y\newline =\sum_{d=1}^N\mu(d)\sum_{T=1}^{N}Td^2\sum_{x=1}^{⌊\frac N{Td}⌋}x\sum_{y=1}^{⌊\frac M{Td}⌋}y\newline 此时令k=Td\newline Ans=\sum_{k=1}^N\sum_{T|k}\mu(⌊\frac kT⌋)k⌊\frac kT⌋\sum_{x=1}^{⌊\frac N{k}⌋}x\sum_{y=1}^{⌊\frac M{k}⌋}y\newline =\sum_{k=1}^Nk\sum_{T|k}\mu(T)T\sum_{x=1}^{⌊\frac N{k}⌋}x\sum_{y=1}^{⌊\frac M{k}⌋}y\newline Ans=x=1Ny=1M(x,y)xy=T=1NT1x=1Ny=1Mxy[(x,y)==T]=T=1NT1x=1TNy=1TMxyT2[(x,y)==1]=T=1NTx=1TNy=1TMxydx,dyμ(d)=d=1Nμ(d)T=1NTdxTNxdyTMy=d=1Nμ(d)T=1NTd2x=1dTNxy=1dTMy=d=1Nμ(d)T=1NTd2x=1TdNxy=1TdMyk=TdAns=k=1NTkμ(Tk)kTkx=1kNxy=1kMy=k=1NkTkμ(T)Tx=1kNxy=1kMy
总算推完了…
此时只需要 Θ ( N ) \Theta(N) Θ(N)线性筛出 ∑ T ∣ k μ ( T ) T \sum_{T|k}\mu(T)T Tkμ(T)T,然后处理 k ∑ T ∣ k μ ( T ) T k\sum_{T|k}\mu(T)T kTkμ(T)T的前缀和
∑ x = 1 ⌊ N k ⌋ x ∑ y = 1 ⌊ M k ⌋ y \sum_{x=1}^{⌊\frac N{k}⌋}x\sum_{y=1}^{⌊\frac M{k}⌋}y x=1kNxy=1kMy可以 Θ ( 1 ) \Theta(1) Θ(1)
利用整除分块优化,时间复杂度为 Θ ( N + T N ) \Theta(N+T\sqrt N) Θ(N+TN )

AC code([bzoj 2693] jzptab)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 10000005, mod = 1e8+9;
int N, M;
namespace Mobius
{
	int mu[MAXN], Prime[MAXN], cnt;
	bool IsnotPrime[MAXN];
	int sum[MAXN];
	void init()
	{
		sum[1] = 1;
		for(int i = 2; i <= MAXN-5; i++)
		{
			if(!IsnotPrime[i]) Prime[++cnt] = i, sum[i] = 1-i;
			for(int j = 1; j <= cnt && i * Prime[j] <= MAXN-5; j++)
			{
				IsnotPrime[i * Prime[j]] = 1;
				if(i % Prime[j] == 0) { sum[i * Prime[j]] = sum[i]; break; }
				sum[i * Prime[j]] = 1ll * sum[i] * (1 - Prime[j]) % mod;
			}
		}
		for(int i = 1; i <= MAXN-5; i++)//前缀和
			sum[i] = (sum[i-1] + 1ll*sum[i]*i%mod) % mod;
	}
	int Sum(int N, int M)
	{
		return ((1ll*N*(N+1)/2) % mod) * ((1ll*M*(M+1)/2) % mod) % mod;
	}
	int calc(int N, int M)
	{
		int ret = 0;
		for(int i = 1, j; i <= N; i=j+1)//整除分块
		{
			j = min(N/(N/i), M/(M/i));
			ret = (ret + 1ll * (sum[j] - sum[i-1]) % mod * Sum(N/i, M/i) % mod) % mod;
		}
		return ret;
	}
}
using namespace Mobius;
int main ()
{
	int T; init();
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &N, &M); if(N > M) swap(N, M);
		printf("%d\n", (calc(N, M) + mod) % mod);
	}
}
AC code([bzoj 2154] Crash的数字表格)

这道题有个恶心的地方,不能用 M a x n Maxn Maxn来预处理,否则会 T L E TLE TLE,要读入 N N N, M M M后再 O ( N ) O(N) O(N)处理

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 10000005, mod = 20101009;
int N, M;
namespace Mobius
{
	int mu[MAXN], Prime[MAXN], cnt;
	bool IsnotPrime[MAXN];
	int sum[MAXN];
	void init()
	{
		sum[1] = 1;
		for(int i = 2; i <= N; i++)
		{
			if(!IsnotPrime[i]) Prime[++cnt] = i, sum[i] = 1-i;
			for(int j = 1; j <= cnt && i * Prime[j] <= N; j++)
			{
				IsnotPrime[i * Prime[j]] = 1;
				if(i % Prime[j] == 0) { sum[i * Prime[j]] = sum[i]; break; }
				sum[i * Prime[j]] = 1ll * sum[i] * (1 - Prime[j]) % mod;
			}
		}
		for(int i = 1; i <= N; i++)
			sum[i] = (sum[i-1] + 1ll*sum[i]*i%mod) % mod;
	}
	int Sum(int N, int M)
	{
		return ((1ll*N*(N+1)/2) % mod) * ((1ll*M*(M+1)/2) % mod) % mod;
	}
	int calc(int N, int M)
	{
		int ret = 0;
		for(int i = 1, j; i <= N; i=j+1)
		{
			j = min(N/(N/i), M/(M/i));
			ret = (ret + 1ll * (sum[j] - sum[i-1]) % mod * Sum(N/i, M/i) % mod) % mod;
		}
		return ret;
	}
}
using namespace Mobius;
int main ()
{
	scanf("%d%d", &N, &M); if(N > M) swap(N, M); init();
	printf("%d\n", (calc(N, M) + mod) % mod);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值