• luogu3601 签到题


    题目大意

    [sum_{i=l}^{r}(i-varphi(i)) ]

    (l,rleq 10^{12}, r-l<10^6)

    思路

    看到这个数据范围,不能直接用线性筛。我们要想求(varphi),需要用时间复杂度为根号的算法(往往是反演)。要想反演,我们要由最朴素的方法中找到思路。
    以下是求一个(varphi(x))值的普速算法的伪代码。

    for the x:
        foreach prime p (in [1, sqrt(x)] && p|x)
            deal(&x, p)
        if(x>1)
            deal_as_big_prime(x)
    

    我们发现枚举的(p)都在(sqrt{x})的范围内。因此我们可以利用每一个([1,sqrt{r}])内的质数求出([l,r])之间的所有(varphi)值。伪代码:

    foreach prime p (in [1, sqrt(r)])
        foreach x[i] (i in [l, r] && p|x[i])//i是x[i]的初始值,x[i]以后会改变
            deal(&x[i], p)
    foreach x[i] (x[i]>1)
        deal_as_big_prime(x[i])
    

    完整代码:

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    #define ll long long
    #define Phi(i) Phis[i - l]
    #define X(i) Xs[i - l]
    
    const int MAX_N = 1000010, P = 666623333;
    ll Phis[MAX_N], Xs[MAX_N];
    int Primes[MAX_N];
    
    int GetPrime(int *prime, int n)
    {
    	static bool NotPrime[MAX_N];
    	int primeCnt = 0;
    	for (int i = 2; i <= n; i++)
    	{
    		if (!NotPrime[i])
    			prime[primeCnt++] = i;
    		for (int j = 0; j < primeCnt; j++)
    		{
    			if (i*prime[j] > n)
    				break;
    			NotPrime[i*prime[j]] = true;
    			if (i%prime[j] == 0)
    				break;
    		}
    	}
    	return primeCnt;
    }
    
    void GetPhi(ll l, ll r, int primeCnt)
    {
    	for (ll i = l; i <= r; i++)
    		Phi(i) = X(i) = i;
    	for (int i = 0; i < primeCnt; i++)
    	{
    		ll lb = Primes[i] * (l / Primes[i]), rb = Primes[i] * (r / Primes[i]);
    		if (lb < l)
    			lb += Primes[i];
    		for (ll j = lb; j <= rb; j+=Primes[i])
    		{
    			Phi(j) = Phi(j) / Primes[i] * (Primes[i] - 1);
    			while (X(j) % Primes[i] == 0)
    				X(j) /= Primes[i];
    		}
    	}
    	for (ll j = l; j <= r; j++)
    		if (X(j) > 1)
    			Phi(j) = Phi(j) / X(j) * (X(j) - 1);
    }
    
    ll StatPhi(ll l, ll r)
    {
    	ll ans = 0;
    	for (ll i = l; i <= r; i++)
    		ans = (ans + i - Phi(i)) % P;
    	return ans;
    }
    
    int main()
    {
    	ll l, r;
    	scanf("%lld%lld", &l, &r);
    	int primeCnt = GetPrime(Primes, sqrt(r));
    	GetPhi(l, r, primeCnt);
    	printf("%lld
    ", StatPhi(l, r));
    	return 0;
    }
    
  • 相关阅读:
    mysql 往表中insert的时候如何让主键id按当前表的最大值自动增长?
    visual studio 2013 win7安装笔记
    mysql奇葩之旅
    java JVM常见的四大异常及处理方案
    DDR3_旧版(2):初始化
    DDR3_旧版(1):IP核调取
    【转】AXI_Lite 总线详解
    ZYNQ笔记(7):AXI从口自定义IP封装
    ZYNQ笔记(6):普通自定义IP封装实现PL精准定时中断
    ZYNQ笔记(5):软中断实现核间通信
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9005479.html
Copyright © 2020-2023  润新知