• 洛谷3172:选数


    洛谷3172:选数

    题意:

    从区间([L,R])选取(N)个整数,总共有((R-L+1)^N)中方案。

    问所有方案中,方案中所有数字的(gcd)等于(K)的方案有多少个。

    对结果(mod 1e9+7)

    数据范围(1leq N,Kleq10^9,1leq Lleq Rleq10^9,R-lleq 10^5)

    思路:

    (F(n))表示从([L,R])中选(N)个数的(gcd)(n)(n)的倍数的情况数。

    (f(n))表示从([L,R])中选(N)个数的(gcd)(n)的情况数。

    很明显有:

    [F(n)=sum_{n|d}f(d) ]

    莫比乌斯反演:

    [f(n)=sum_{n|d}F(d)mu(frac{d}{n}) ]

    答案是(f(K))

    但是(f(K))不太好求,因为这个倍数其实不是很方便枚举,(f(1))是相对好求的。

    所以我们只需要在区间([frac{L}{K},frac{R}{K}])(f(1))就好了。

    但这里有个问题,就是如果(L\%K eq 0),那么就会有(lfloorfrac{L}{K} floor *K<L),会使一些不在([L,R])范围内的数混入答案当中,所以这里加个特判,如果(L\%k eq 0),就有(L=L/K+1)

    接着考虑(F(n))怎么求?

    我们知道

    [gcd(a,b)=d\ ]

    有:

    [d|a,d|b ]

    所以(F(n))就比较好求了,其实就是([L,R])区间范围内,(n)的倍数的个数的(N)次方。

    [F(n)=(lfloorfrac{R}{n} floor-lfloorfrac{L-1}{n} floor )^N ]

    答案就是:

    [f(1)=sum_{1|d}F(d)mu(d)\=sum_{d=1}^{R}mu(d)(lfloorfrac{R}{d} floor-lfloorfrac{L-1}{d} floor )^N ]

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 5e6;
    const int mod = 1e9 + 7;
    
    int primes[maxn+10], cnt;
    bool vis[maxn+10];
    ll mu[maxn+10];
    void init(int n)
    {
        mu[1] = 1;
        for(int i = 2; i <= n; i++)
        {
            if(!vis[i])
            {
                primes[++cnt] = i;
                mu[i] = -1;
            }
            for(int j = 1; primes[j] <= n/i; j++)
            {
                vis[primes[j]*i] = 1;
                if(i % primes[j] == 0) break;
                else mu[i*primes[j]] = -mu[i];
            }
        }
        for(int i = 1; i <= n; i++)
            mu[i] += mu[i-1];
    }
    
    ll qmi(ll a, ll b)
    {
        a %= mod;
        ll res = 1; res %= mod;
        while(b)
        {
            if(b&1) res = (res*a)%mod;
            a = (a*a)%mod;
            b >>= 1;
        } return res%mod;
    }
    
    unordered_map<ll, ll> Smu;
    inline ll getSmu(ll n)
    {
        if(n <= maxn) return mu[n];
        if(Smu[n]) return Smu[n];
        ll res = 1;
        for(ll l = 2, r; l <= n; l = r+1)
        {
            r = n/(n/l);
            res -= (r-l+1)%mod*getSmu(n/l)%mod;
            res = (res%mod+mod)%mod;
        } return Smu[n] = res;
    }
    
    ll N, K, L, R;
    
    int main()
    {
        init(maxn);
        cin >> N >> K >> L >> R;
        R /= K;
        if(L % K == 0) L = L/K;
        else L = L/K+1;
    
        L = L-1; ll ans = 0;
        for(ll l = 1, r; l <= R; l = r+1)
        {
            if(L/l == 0) r = R/(R/l);
            else r = min(R/(R/l), L/(L/l));
            ans = (ans+qmi(R/l-L/l, N)%mod*(getSmu(r)-getSmu(l-1))%mod)%mod;
        }
        cout << (ans%mod+mod)%mod << endl;
        return 0;
    }
    
  • 相关阅读:
    mysql常用函数
    主程Ry访谈录
    mongodb spring anno 查询
    mongodb 查询少少优化
    jquery table thead drop
    ubuntu 配置java,eclipse ,flex,zend,php,TomCat环境
    mongodb shell
    TCP/IP Sockets in Java 源码
    java 断点下载
    直线生成 DDA
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12266092.html
Copyright © 2020-2023  润新知