zoukankan      html  css  js  c++  java
  • poj 2154:Color【polya计数,Euler函数】


    http://poj.org/problem?id=2154

    poj 2154:Color
    http://blog.sina.com.cn/s/blog_6f71bea30100opru.html

    大意:n种颜色的珠子可组成多少种长度为n的项链?
    这题和2409 类似,不同之处在于,只考虑旋转,不考虑翻转;
    因此相对前面两个题目应该说是更简单,但一看数据范围,
    就不是这么回事了,2409完全可以直接循环处理,
    但这题目n最大达100000000,显然会TLE,故需寻求更佳的解决方案。
    用欧拉函数进行优化:

    旋转:顺时针旋转i格的置换中,循环的个数为gcd(i,n),每个循环的长度L为n/gcd(i,n)。
    如果枚举旋转的格数i,复杂度显然较高。有没有好方法呢?可以不枚举i,反过来枚举L。
    由于L|N,枚举了L,再计算有多少个i使得0<=i<=n-1并且gcd(i,n)=n/L。
    不妨设a=n/L=gcd(i, n),
    不妨设i=a*t则当且仅当gcd(L,t)=1时
    Gcd(i,n)=gcd(a*L,a*t)=a。
    因为0<=i<n,所以0<=t<n/a=L.
    所以满足这个条件的t的个数为Euler(L).

    #include<stdio.h>
    #include<string.h>
    
    const int N = 36000;
    int prime[N];
    int pnum;
    bool isp[N];
    int  mod;
    void getPrim()
    {
     int i,j;
     pnum = 0;
     memset(isp,true,sizeof(isp));
     for(i=2;i<N;i++)
      if(isp[i])
      {
       prime[pnum++]=i;
       for(j=i+i;j<N;j+=i)
        isp[j]=false;
      }
    
     // for(i=0;i<10;i++)
      // printf("%d ",prime[i]);
    }
    
    int  Eular(int  n)
    {
       int  i;
       int  ret = n;
       if(n==1)return 1;
       for(i=0;prime[i]*prime[i]<=n;i++)
       {
        if(n%prime[i]==0)
        {
         ret-=ret/prime[i];
         while(n%prime[i]==0)n/=prime[i];
         if(n==1)break;
        }
       }
    
       if(n!=1)ret-=ret/n;
       return ret;
    }
    
     
    
    int  getPow(int  a,int  l,int  mod)
    {
     int  ans = 1;
     a=a%mod;
        while(l)
     {
      if(l&1)ans=(ans*a)%mod;
      l>>=1;
      a=(a*a)%mod;
     }
     return ans;
    }
    int main()
    {
     getPrim();
     int T;
     scanf("%d",&T);
     {
           while(T--)
        {
         int  a,l;
         int  ans = 0;
         scanf("%d%d",&a,&mod);
         for(l=1;l*l<a;l++)
         {
          if(a%l==0)
          {
                     int  x = Eular(l)%mod;
         int  c = getPow(a,a/l-1,mod);
         ans=(ans+c*x%mod)%mod;
          x = Eular(a/l)%mod;
          c = getPow(a,l-1,mod);
          ans=(ans+c*x%mod)%mod;
          }
         }
         if(l*l==a)
         {
                  int  x = Eular(l)%mod;
         int  c = getPow(a,a/l-1,mod);
         ans=(ans+c*x%mod)%mod;
         }
    
         printf("%d\n",ans);
        }
    
    
     }
     return 0;
    }
    
  • 相关阅读:
    《临江仙·滚滚长江东逝水》
    .net Core Newtonsoft.Json 解析巨坑之注释影响代码
    C# 后端post请求帮助类
    鼠标点击事件
    常用Windows 消息列表
    WinUser.h>>>OnMessage事件
    Jellyfin流媒体服务器搭建和一些小坑
    ios开发遇到的问题
    节省你的时间,用AHK实现随机打开文件
    一些简单的AHK脚本提升电脑使用体验
  • 原文地址:https://www.cnblogs.com/AndreMouche/p/1956201.html
Copyright © 2011-2022 走看看