zoukankan      html  css  js  c++  java
  • [bzoj 2693] jzptab & [bzoj 2154] Crash的数字表格 (莫比乌斯反演)

    题目描述

    TT组数据,给出NN,MM,求x=1Ny=1Mlim(x,y)sum_{x=1}^Nsum_{y=1}^M lim(x,y) ewline
    N,M<=10000000T<=10000N,M <= 10000000 ewline T<= 10000

    题目分析

    直接开始变换,假设N<M
    Ans=x=1Ny=1Mxy(x,y)=T=1N1Tx=1Ny=1Mxy[(x,y)==T]=T=1N1Tx=1NTy=1MTxyT2[(x,y)==1]=T=1NTx=1NTy=1MTxydx,dyμ(d)=d=1Nμ(d)T=1NTdxNTxdyMTy=d=1Nμ(d)T=1NTd2x=1NTdxy=1MTdy=d=1Nμ(d)T=1NTd2x=1NTdxy=1MTdyk=TdAns=k=1NTkμ(kT)kkTx=1Nkxy=1Mky=k=1NkTkμ(T)Tx=1Nkxy=1Mky Ans=sum_{x=1}^Nsum_{y=1}^M frac {xy}{(x,y)} ewline =sum_{T=1}^Nfrac 1Tsum_{x=1}^Nsum_{y=1}^Mxy[(x,y)==T] ewline =sum_{T=1}^Nfrac 1Tsum_{x=1}^{⌊frac NT⌋}sum_{y=1}^{⌊frac MT⌋}xyT^2[(x,y)==1] ewline =sum_{T=1}^NTsum_{x=1}^{⌊frac NT⌋}sum_{y=1}^{⌊frac MT⌋}xysum_{d|x,d|y}mu(d) ewline =sum_{d=1}^Nmu(d)sum_{T=1}^{N}Tsum_{d|x}^{⌊frac NT⌋}xsum_{d|y}^{⌊frac MT⌋}y ewline =sum_{d=1}^Nmu(d)sum_{T=1}^{N}Td^2sum_{x=1}^{⌊frac{⌊frac NT⌋}d⌋}xsum_{y=1}^{⌊frac{⌊frac MT⌋}d⌋}y ewline =sum_{d=1}^Nmu(d)sum_{T=1}^{N}Td^2sum_{x=1}^{⌊frac N{Td}⌋}xsum_{y=1}^{⌊frac M{Td}⌋}y ewline 此时令k=Td ewline Ans=sum_{k=1}^Nsum_{T|k}mu(⌊frac kT⌋)k⌊frac kT⌋sum_{x=1}^{⌊frac N{k}⌋}xsum_{y=1}^{⌊frac M{k}⌋}y ewline =sum_{k=1}^Nksum_{T|k}mu(T)Tsum_{x=1}^{⌊frac N{k}⌋}xsum_{y=1}^{⌊frac M{k}⌋}y ewline
    总算推完了…
    此时只需要Θ(N)Theta(N)线性筛出Tkμ(T)Tsum_{T|k}mu(T)T,然后处理kTkμ(T)Tksum_{T|k}mu(T)T的前缀和
    x=1Nkxy=1Mkysum_{x=1}^{⌊frac N{k}⌋}xsum_{y=1}^{⌊frac M{k}⌋}y可以Θ(1)Theta(1)
    利用整除分块优化,时间复杂度为Θ(N+TN)Theta(N+Tsqrt N)

    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
    ", (calc(N, M) + mod) % mod);
    	}
    }
    
    AC code([bzoj 2154] Crash的数字表格)

    这道题有个恶心的地方,不能用MaxnMaxn来预处理,否则会TLETLE,要读入NN,MM后再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
    ", (calc(N, M) + mod) % mod);
    }
    
  • 相关阅读:
    Sum Root to Leaf Numbers 解答
    459. Repeated Substring Pattern
    71. Simplify Path
    89. Gray Code
    73. Set Matrix Zeroes
    297. Serialize and Deserialize Binary Tree
    449. Serialize and Deserialize BST
    451. Sort Characters By Frequency
    165. Compare Version Numbers
    447. Number of Boomerangs
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039466.html
Copyright © 2011-2022 走看看