zoukankan      html  css  js  c++  java
  • ACM-ICPC 2018 徐州赛区网络预赛 D. EasyMath

    ACM-ICPC 2018 徐州赛区网络预赛 D. EasyMath


    做法:

    [f(m,n) = sum _{i=1}^{m} mu(in) = sum_{i=1}^{m}[gcd(i,n)=1]mu(i)mu(n) = mu(n)sum_{d|n}mu(d)f(frac{m}{d},d) ]

    边界: n=1,杜教筛求(sum_{i=1}^{m}mu(i)),m = 1, 返回(mu(n)),预处理尽可能把空间卡满。

    2个小时的时候就推出来了这个式子,不会算复杂度,本校没人过。。。于是成功放弃了。。。

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define mp make_pair
    #define PII pair<int,int>
    #define sc second
    typedef long long ll;
    const int N = 1e7 + 13000000 + 1;
    const int LM = 13000000;
    using namespace std;
    ll n,m;
    bool notp[N];
    int p[N], smiu[N];
    short miu[N];
    void init() {
        notp[1] = 1;
        miu[1] = 1;
        for(int i=2;i<=1e7+LM;++i) {
            if(!notp[i]) p[++p[0]] = i, miu[i] = -1;
            for(int j=1;j<=p[0]&&p[j]*i<=1e7+LM;++j) {
                notp[i*p[j]] = 1;
                if(i%p[j] == 0) {
                    miu[i*p[j]] = 0;
                    break;
                }
                miu[i*p[j]] = miu[i]*miu[p[j]];
            }
        }
        for(int i=1;i<=1e7+LM;++i) smiu[i] = smiu[i-1] + miu[i];
    }
    ll g(ll n) {
        if(n<=1e7+LM) return smiu[n];
        if(n == 1) return 1;
        ll ans = 1;
        for(ll i=2,r;i<=n;i=r+1) {
            r = (n/(n/i));
            ans -= (r-i+1LL)*g(n/i);
        }
        return ans;
    }
    void chai(ll x,vector<ll> &v,ll &mu) {
        v.clear();
        mu = 1;
        for(int i=1;i<=p[0]&&1LL*p[i]*p[i]<=x;++i) {
            if(x%p[i]==0) {
                int cnt = 0;
                v.pb(p[i]);
                mu = -mu;
                while(x%p[i]==0) x/=p[i], cnt++;
                if(cnt>1) mu = 0;
            }
        }
        if(x!=1) mu=-mu, v.pb(x);
    }
    ll f(ll m,ll n) {
        if(m == 0 || n == 0) return 0;
        ll mu_n, ans = 0;
        if(m == 1 && n <= 1e7+LM) return miu[n];
        vector<ll> v;
        chai(n,v,mu_n);
        if(m == 1) return mu_n;
        if(n == 1) return g(m);
        if(mu_n == 0) return 0;
        int cnt = v.size();
        for(int s=0;s<(1<<cnt);++s) {
            ll d = 1, mu_d = 1;
            for(int i=0;i<cnt;++i) if(s&(1<<i)){
                d = d*v[i];
                mu_d = -mu_d;
            }
            if(m >= d) ans += mu_d*f(m/d,d);
        }
        ans *= mu_n;
        return ans;
    }
    
    int main() {
        init();
        scanf("%lld%lld",&m,&n);
        printf("%lld
    ",f(m,n));
        return 0;
    }
    
    
  • 相关阅读:
    java 基础笔记 基本数据类型对象包装类
    java String 类 基础笔记
    java 线程 笔记 基础
    java 线程 基础笔记2
    java 异常学习 笔记
    广告简单概念整理-持续更新
    curl一些使用技巧
    简单学习正则表达式
    Linux命令简单操作之lsof
    Linux命令简单操作之find和xargs
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9615109.html
Copyright © 2011-2022 走看看