• poj 2154 Color


    Color

    题意:有N种颜色,项链上有N颗珠子;(1 <= N <= 1e^9)每种颜色的珠子有无限个;问通过旋转操作有多少种不同的项链;

    思路:等价类计数问题 + 欧拉函数优化;

    等价类计数:

    旋转:旋转i颗珠子的间距;0,i,2i...构成一个循环;这个循环有n/gcd(n,i)颗珠子,总共有gcd(n,i)个循环;所以不动点总数的平均值就为 1/N*Σ(1 <= i <= n)  Ngcd(i,n)

    优化:朴素算法的时间复杂度是O(n*log(n)),gcd的时间复杂度要小于log(n);实际上我们是枚举了i,通过gcd来求出循环节的个数的;易知循环节的个数d是n的约数(不只是素数),这可以在sqrt(n)内求解;如果我们通过枚举d来求出有多少k满足gcd(k,n) = d (欧拉函数)

    gcd(k,n) = d,gcd(k/d,n/d) = 1,(1 <= k <= n) ==>gcd(k,n/d) = 1(1 <= k <= n/d);即 num(k) = Φ(n/d);这样公式就转化为Σd|n[Φ(N/d)*N(d-1)]

    那时间复杂度就是sqrt(n)*log(n)*(约数个数);

    注:这题在循环终止上要特别注意,否则容易TLE,卡常数。这道题将近1s才过..前几次在phi中卡了常数TLE了;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    #include<stack>
    #include<set>
    #include<map>
    #include<queue>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define MSi(a) memset(a,0x3f,sizeof(a))
    #define inf 0x3f3f3f3f
    #define lson l, m, rt << 1
    #define rson m+1, r, rt << 1|1
    typedef __int64 ll;
    template<typename T>
    void read1(T &m)
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        m = x*f;
    }
    template<typename T>
    void read2(T &a,T &b){read1(a);read1(b);}
    template<typename T>
    void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);}
    template<typename T>
    void out(T a)
    {
        if(a>9) out(a/10);
        putchar(a%10+'0');
    }
    const int MAXN = 5e4;
    int prime[MAXN],check[MAXN];
    void getprime()
    {
        int i,j;
        for(i = 2;i < MAXN;i++){
            if(check[i] == 0) prime[++prime[0]] = i;
            for(j = 1;j <= prime[0] && prime[j] < MAXN/i;j++){
                check[prime[j]*i] = 1;
                if(i%prime[j] == 0) break;
            }
        }
    }
    int N,p;
    int phi(int d)
    {
        int ans = d,tmp = d;
        for(int i = 1;prime[i]*prime[i] <= tmp;i++){//i <= prime[0] && prime[i] <= tmp 卡常数
            if(tmp%prime[i] == 0)
                ans -= ans/prime[i];
            while(tmp % prime[i] == 0) tmp /= prime[i];
        }
        if(tmp != 1) ans -= ans/tmp;
        return ans%p;
    }
    int pow_mod(int a,int n)
    {
        if(n == 0) return 1;
        if(n == 1) return a;
        int ans = pow_mod(a,n/2);
        (ans = ans*ans) %= p;
        if(n & 1) ans = ans*a%p;
        return ans;
    }
    int main()
    {
        int X;
        read1(X);
        getprime();
        while(X--){
            read2(N,p);
            int ans = 0, tmp = sqrt(N)+0.5;
            for(int i = 1;i <= tmp;i++){ //只需整除即可,未必是素数;
                if(N % i) continue;
                (ans += phi(N/i)*pow_mod(N%p,i-1)) %= p;
                if(N != i*i)
                    (ans += phi(i)*pow_mod(N%p,N/i-1)) %= p;
            }
            out(ans);
            puts("");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    failonerror on MSBuild
    近期Windows Mobile问题汇总
    android的文件操作 sdcard和rom
    用实际库存数调整批次保留最新的批次
    各种布局layout
    javascript让ui线程让出时间片的模型
    android ListView控件操作绑定数据、单击事件
    Pocket PC 模拟器上网设置
    android单元测试
    打电话发短信
  • 原文地址:https://www.cnblogs.com/hxer/p/5224872.html
Copyright © 2020-2023  润新知