zoukankan      html  css  js  c++  java
  • [HDU 5608]Function(莫比乌斯反演 + 杜教筛)

    题目描述

    N23N+2=dNf(d)N^2-3N+2=sum_{d|N} f(d)
    i=1Nf(i)sum_{i=1}^{N} f(i)  mod 109+7~mod~10^9+7
    1<=T<=5001<=N<=1091<=T<=500\1<=N<=10^9
    只有最多55组数据N>106N>10^6

    题目分析

    f(n)=n23n+2dn,d<nf(d)S(n)=i=1n(i23i+2di,d<if(d))                      =i=1ni23i=1ni+2nk=2nd=1nkf(d)                    =i=1ni23i=1ni+2nk=2nS(nk)                    =n(n+1)(n4)3+2nk=2nS(nk) f(n)=n^2-3n+2-sum_{d|n,d<n}f(d)\ herefore S(n)=sum_{i=1}^n(i^2-3i+2-sum_{d|i,d<i}f(d))\ =sum_{i=1}^ni^2-3sum_{i=1}^ni+2n-sum_{k=2}^nsum_{d=1}^{lfloorfrac nk floor}f(d)\ =sum_{i=1}^ni^2-3sum_{i=1}^ni+2n-sum_{k=2}^nS({lfloorfrac nk floor})\ =frac {n(n+1)(n-4)}3+2n-sum_{k=2}^nS({lfloorfrac nk floor})
    如此一来就可以杜教筛了,然而仅仅这样还是会T,于是我们在想一想如何筛出前面一部分的ff
    g(n)=n23n+2g(n)=n^2-3n+2,根据莫比乌斯反演
    f(n)=dnμ(nd)g(d) herefore f(n)=sum_{d|n}mu(lfloorfrac nd floor)g(d)
    于是用Θ(106ln(106))Theta (10^6ln(10^6))筛出前10610^6项就行了
    总时间复杂度Θ(106ln(106)+T+5n23)Theta(10^6ln(10^6)+T+5n^{frac 23})

    AC code:
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    using namespace std;
    const int MAXN = 1000001;
    const int mod = 1e9+7;
    const int inv3 = 333333336;
    
    inline int g(int n)
    {
    	return (1ll * n * n % mod - 3ll * n % mod + 2) % mod;
    }
    
    int Prime[MAXN], Cnt, mu[MAXN], f[MAXN];
    bool IsnotPrime[MAXN];
    
    void init()
    {
    	mu[1] = 1;
    	for(int i = 2; i < MAXN; ++i)
    	{
    		if(!IsnotPrime[i]) Prime[++Cnt] = i, mu[i] = -1;
    		for(int j = 1; j <= Cnt && i * Prime[j] < MAXN; ++j)
    		{
    			IsnotPrime[i * Prime[j]] = 1;
    			if(i % Prime[j] == 0)
    			{
    				mu[i * Prime[j]] = 0;
    				break;
    			}
    			mu[i * Prime[j]] = -mu[i];
    		}
    	}
    	for(int i = 1; i < MAXN; ++i)
    		for(int j = i; j < MAXN; j+=i)
    			f[j] = (f[j] + 1ll * mu[j/i] * g(i) % mod) % mod;
    	for(int i = 1; i < MAXN; ++i) f[i] = (f[i-1] + f[i]) % mod;
    }
    map<int,int>F;
    inline int solve(int n)
    {
    	if(n < MAXN) return f[n];
    	if(F.count(n)) return F[n];
    	int ret = (1ll * n * (n+1) % mod * (n-4) % mod * inv3 % mod + 2ll*n%mod) % mod;
    	for(int i = 2, j; i <= n; i=j+1)
    	{
    		j = n/(n/i);
    		ret = (ret - 1ll * (j-i+1) * solve(n/i) % mod) % mod;
    	}
    	return F[n]=ret;
    }
    
    int main()
    {
    	init();
    	int T, n;
    	scanf("%d", &T);
    	while(T--)
    	{
    		scanf("%d", &n);
    		printf("%d
    ", (solve(n)+mod)%mod);
    	}
    }
    
  • 相关阅读:
    如何计算二进制数的取值范围
    理解网络请求中的连接超时和读取超时
    两行代码玩转Spring Data排序和分页
    面试必问Elasticsearch倒排索引原理
    你知道Java的四种引用类型吗
    抛弃配置后的Spring终极教程
    Python学习第二篇
    Python
    关于always块内for循环的执行方式
    三态门实现“一读多写”总线结构
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039462.html
Copyright © 2011-2022 走看看