zoukankan      html  css  js  c++  java
  • 题解 poj 2154 Color

    传送门


    【题意】

    (x) 组数据

    每组询问 (n) 个颜色填涂 (n) 个空位的环,问不同构方案数,答案对 (p) 取模。

    规定某个环能被另一个环旋转得到时,这两个环同构。

    (xleq 3500, nleq 10^9)


    【分析】

    显然 (n) 个角度的旋转构成一个群,根据 polya 定理,得到答案为:

    (displaystyle {1over n}sum_{i=1}^n n^{gcd(i, n)}={1over n}sum_{dmid n} n^d oldsymbol varphi({nover d})=sum_{dmid n} n^{d-1} oldsymbol varphi({nover d}))

    但如果暴力计算每一个 (oldsymbol varphi({nover d})) 复杂度为 (O(n^{3over 4})) 可能不够,考虑先打出前 ({n^{3over 5}}) 个欧拉函数值,则求解所有欧拉函数的复杂度降低为 (O(n^{3over 5}))(证明如下)

    故求解一组的复杂度为 (O(n^{3over 5})+O(sqrt n)+O(sqrt nlog n)=O(n^{3over 5})),总复杂度即为 (O(xcdot n^{3over 5})),卡卡常能过


    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<ll, ll> pii;
    typedef double db;
    #define fi first
    #define se second
    int n, mod;
    inline int fpow(int a,int x) { ll ans=1; for(;x;x>>=1,a=(ll)a*a%mod) if(x&1) ans=(ll)ans*a%mod; return ans; }
    const int Lim=2.6e5, MAXN=Lim+10;
    int fc[MAXN], phi[MAXN], prime[MAXN], cntprime;
    inline int getphi(int n) {
        if(n<=Lim) return phi[n];
        int val=n;
        for(int j=1;j<=cntprime;++j)
            if((ll)prime[j]*prime[j]>n) break;
            else if(n%prime[j]==0){
                val=val/prime[j]*(prime[j]-1);
                while(n%prime[j]==0) n/=prime[j];
            }
        if(n!=1) val=val/n*(n-1);
        return val;
    }
    inline int ans(){
        int res=0;
        for(int i=1;i*i<=n;++i) if(n%i==0) {
            int j=n/i;
            res+=(ll)getphi(j)*fpow(n, i-1)%mod;
            res-=(res>=mod?mod:0);
            if(i!=j){
                res+=(ll)getphi(i)*fpow(n, j-1)%mod;
                res-=(res>=mod?mod:0);
            }
        }
        return res;
    }
    inline void sieve(){
        phi[1]=1;
        for(int i=2;i<=Lim;++i){
            if(!fc[i]) fc[i]=prime[++cntprime]=i, phi[i]=i-1;
            for(int j=1;j<=cntprime;++j)
                if(prime[j]*i>Lim||prime[j]>fc[i]) break;
                else fc[prime[j]*i]=prime[j], phi[prime[j]*i]=phi[i]*(prime[j]-(prime[j]!=fc[i]));
        }
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        sieve();
        int x; cin>>x;
        while(x--&&cin>>n>>mod) cout<<ans()<<"
    ";
        cout.flush();
        return 0;
    }
    

    【证明】

    朴素求解所有欧拉函数的复杂度求解如下考虑:

    由于每个数字 (n) ,设其存在一个严格小于 (sqrt n) 的因数 (d) ,则必然同时存在一严格大于 (sqrt n) 的因数 ({nover d})

    故因数个数至多为 (2cdot(sqrt n-1)+1=2sqrt n-1)

    我们朴素求解 (n) 的欧拉函数值,复杂度为 (O(sqrt n))

    (displaystyle T(n)=sum_{dmid n}Ccdot sqrt dleq Csum_{d=1}^{sqrt n}(sqrt d+sqrt {nover d}))

    由于 (displaystyle sum_{x=1}^{sqrt n} sqrt xapprox int_1^{sqrt n}x^{1over 2} ext dx={2over 3}(x^{3over 2}|^{sqrt n}_1)=O(n^{3over 4}))

    (displaystyle sum_{x=1}^{sqrt n} {1over sqrt x}approx int_1^{sqrt n} x^{-{1over 2}} ext dx=2(x^{1over 2}|^{sqrt n}_1)=O(n^{1over 4}))

    (T(n)=Ccdot O(n^{3over 4})+Ccdot sqrt ncdot O(n^{1over 4})=O(n^{3over 4}))

    此为朴素计算的复杂度

    考虑有限筛出 (m) 范围内欧拉函数的值,由上述朴素的分析得到:

    (m<sqrt n) ,则前半部分时间复杂度减小,后半部分不变,总复杂度为 (O(m)+o(n^{3over 4})+O(n^{3over 4})=O(n^{3over 4}))

    (mgeq sqrt m),此时可得,后半部分的因数均大于 (m),故其对应的小因数均小于 ({nover m})

    故复杂度化为 (displaystyle T(n)=O(m)+sum_{i=1}^{nover m}Ccdot sqrt{nover i}=O(m)+Ccdot sqrt ncdot O(({nover m})^{1over 4})=O(m)+O({n^{3over 4}over m^{1over 4}}))

    (displaystyle T(n)=C_1m+C_2cdot {n^{3over 4}over m^{1over 4}})

    根据均值不等式,(displaystyle C_1m=C_2cdot {n^{3over 4}over m^{1over 4}})(T(n)) 取最小值,达到 (O(m))

    求解等式得到 (m=({C_2over C_1})^{4over 5}cdot n^{3over 5})

    由于我也不知道 (C_1, C_2) 的值,故均取 (1),得到 (T(n)=O(m)=O(n^{3over 5}))

  • 相关阅读:
    百度语音
    前端技术
    自动化测试
    分布式锁
    缓存穿透、缓存击穿、缓存雪崩
    延迟队列
    Arthas
    MyBatis配置文件容易引发的不容易发现的问题(驼峰式命名)
    JUnit使用中遇到的问题
    使用ArrayList<E>遇到的数据重复问题
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14994213.html
Copyright © 2011-2022 走看看