zoukankan      html  css  js  c++  java
  • 【POJ 2154】Color

    Solution

    怎么说,这里是记录一个玄学优化吧。

    先列出 (Polya) 定理吧:

    [ans=frac{1}{|G|}sum_{k=1}^{g}m^{c(sigma_k)} ]

    这道题只有旋转,于是我们的 (|G|==g) 就是 n 啦,而表示颜色种数的 m 也是 n 啦。

    但是康康 n 的范围:(1e9) 艹!

    于是我们调转枪头,我们发现循环节的长度相同时,此时的 i 不一定相同,这就是我们优化的突破口。

    设 L 为循环节长度,易得 (L=frac{n}{gcd(i,n)}),其中 (gcd(i,n)) 是循环节的个数。

    再设 (cnt=gcd(i,n)=frac{n}{L})

    因为 (cnt|i),所以可令 (i=t*cnt)。(因为 (1<=i<=n),所以 (1<=t<=frac{n}{cnt}=L)

    所以有:(gcd(i,n)==gcd(t*cnt,L*cnt)==cnt)

    上面这个式子就是使循环节长度为 L 的条件。

    易得当 (gcd(t,L)==1) 时满足条件。

    L 是可以以 (O(sqrt n)) 的复杂度枚举的,求出此时合法的 t 的个数就转换成了求 (phi(L))

    然后直接套上去就行了。

    注意的是我们这里用两种求 (phi) 的方法为了降低点运行时间。直接算 (phi) 的那个方法可以证明我们之前筛的素数是够用的,因为我们先前筛的素数是 (1e6) 范围内,而 n 的范围是 (1e9) 之内,可以保证超过我们预处理范围的素数至多只有一种。

    Code

    上马!(/xyx

    #include <cstdio>
    
    const int N = 1e6;
    
    int n, mod, cnt, phi[N + 5], p[N + 5];
    bool vis[N + 5];
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    int Phi(int n) {
        if(n <= N) return phi[n] % mod;
        int ans = n;
        for(int i = 1; i <= cnt && p[i] * p[i] <= n; ++ i) {
            if(n % p[i] == 0) {
                ans -= ans / p[i];
                while(n % p[i] == 0) n /= p[i];
            }
        }
        if(n > 1) ans -= ans / n;
        return ans % mod;
    }
    
    void Euler() {
        phi[1] = 1;
        for(int i = 2; i <= N; ++ i) {
            if(! vis[i]) p[++ cnt] = i, phi[i] = i - 1;
            for(int j = 1; j <= cnt && p[j] * i <= N; ++ j) {
                vis[p[j] * i] = 1;
                if(i % p[j] == 0) {
                    phi[p[j] * i] = phi[i] * p[j];
                    break;
                }
                else phi[p[j] * i] = phi[i] * (p[j] - 1);
            }
        }
    }
    
    int qkpow(int x, int y) {
        int res = 1; x %= mod;
        while(y) {
            if(y & 1) (res *= x) %= mod;
            (x *= x) %= mod, y >>= 1;
        }
        return res;
    }
    
    int Polya() {
        int ans = 0;
        for(int i = 1; i * i <= n; ++ i) {
            if(n % i) continue;
            (ans += Phi(i) * qkpow(n, n / i - 1)) %= mod;
            if(i * i == n) break;
            (ans += Phi(n / i) * qkpow(n, i - 1)) %= mod;//减一是为了消去 Polya 式子前的那个分数
        }
        return ans;
    }
    
    int main() {
        Euler();
        for(int T = read(); T; -- T) {
            n = read(), mod = read();
            printf("%d
    ", Polya());
        }
        return 0;
    }
    
  • 相关阅读:
    python 数据可视化(一)
    python unittest自动测试框架
    使用selenium抓取淘宝信息并存储mongodb
    python之re模块(正则表达式)
    [原] OpenGL ES 学习笔记 (二)
    [原] OpenGL ES 学习笔记 (一)
    [转] iOS开发同学的arm64汇编入门
    [转]ARM64 汇编
    [转]iOS高级调试&逆向技术-汇编寄存器调用
    [转] CGTime CMTimeRange CMTimeMapping 小结
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12704364.html
Copyright © 2011-2022 走看看