POJ 2154 【POLYA】【欧拉】

前记:

TM终于决定以后干啥了。这几天睡的有点多。困饿交加之间喝了好多水。可能是灌脑了。

切记两件事:

1.安心当单身狗

2.顺心码代码

题意:

给你N种颜色的珠子,串一串长度问N的项链,要求旋转之后重合的算是同一种项链。问一共有多少中可能。结果模p。

1 <= N <= 1000000000, 1 <= P <= 30000

思路:

首先是我们的POLYA定理,给定的公式是这样的sigma(N^gcd(N,i))/N   i从0到N-1.

然后是优化的问题。因为如果我们枚举i累加一定会超时。

这道题考虑的是gcd(N,i)的种类是有限的。我们只要求出每种gcd有多少个就可以了。

考虑N=X*GCD I=Y*GCD

由此我们知道gcd(x,y)一定是1.

所以考虑枚举x,GCD的个数应该是x的欧拉。

坑点:

春困。TM变量总是写错。这道题的减一来源于提前把N给除掉了【这个N经常容易被人忽略】

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
using namespace std;
int prime[100000];//0代表是素数
int tmp[100000];//素数的序列
int part[100000];//将t分解
int num[100000];//每个质因数的分解数量
int jilu[100000];//dfs记录某个质因数用了几个
long long ans,t,p;//t是N,p是p
int partn;//记录一共分解成了几种素数
void fprime()//筛法打表
{
    int atmp=0,j;
    for(int i=2;i<100000;i++)
    {
        if(!prime[i])
        {
            tmp[atmp++]=i;
        }
        for(j=0;j<atmp;j++)
        {
            if(i*tmp[j]>=100000)
                break;
            prime[i*tmp[j]]=1;
            if(i%tmp[j]==0)
                break;
        }
    }
}
void depart(int t){
    int sq=sqrt(t)+1;
    for(int i=0;tmp[i]<=sq;i++){
            if(t%tmp[i]==0){
                part[partn]=tmp[i];
                while(t%tmp[i]==0){
                    num[partn]++;
                    t/=tmp[i];
                }
                partn++;
            }
    }
    if(t>1){
        part[partn]=t;
        num[partn]=1;
        partn++;
    }
}
void init(){
    memset(num,0,sizeof(num));
    partn=0;
    ans=0;
}
long long quick_pow(long long a,long long b){
    long long rel=1;
    while(b){
        if(b&1){
            rel*=a;
            rel%=p;
        }
        a*=a;
        a%=p;
        b>>=1;
    }
    return rel;
}
long long oula(){
    long long rel=1;
    for(int i=0;i<=partn;i++){
        if(jilu[i]){
            rel*=(part[i]-1)*quick_pow(part[i],jilu[i]-1);
            rel%=p;
        }
    }
    return rel;
}
void dfs(int pos,long long nnum){
    if(pos>partn){
        long long a=oula();
        long long b=quick_pow(t,t/nnum-1);
        ans+=(a%p)*(b%p)%p;
        ans%=p;
        return;
    }
    long long ttt=1;
    for(int i=0;i<=num[pos];i++){
        jilu[pos]=i;
        dfs(pos+1,nnum*ttt);
        ttt*=part[pos];
    }
}
int main()
{
    fprime();
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%I64d%I64d",&t,&p);
        init();
        depart(t);
        partn--;
        dfs(0,1);
        printf("%I64d\n",ans);
    }
}
时间: 2024-08-09 06:34:15

POJ 2154 【POLYA】【欧拉】的相关文章

poj 2154 Color 欧拉函数优化的ploya计数

枚举位移肯定超时,对于一个位移i,我们需要的是它的循环个数,也就是gcd(i,n),gcd(i,n)个数肯定不会很多,因为等价于n的约数的个数. 所以我们枚举n的约数,对于一个约数k,也就是循环个数为n/k这样的个数有phi[k]种,证明网上有很多.所以答案就是 phi[k]*(pow(n,n/k)) (k是n的所有约数) 由于约数会很大所以不能打表,只能单个算. 再由于最后要除以n,如果做除法就不能直接取模,所以我们在算每一次pow(n,n/k)的时候,都少乘一个n,这样就相当于除法了. #i

[POJ 2407]Relatives(欧拉函数)

Description Given n, a positive integer, how many positive integers less than n are relatively prime to n? Two integers a and b are relatively prime if there are no integers x > 1, y > 0, z > 0 such that a = xy and b = xz. Input There are several

POJ 2407 Relatives 欧拉函数题解

最基本的欧拉函数: 欧拉函数:求小于n的与n互质的个数 欧兰函数公式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)-..(1-1/pn),其中p1, p2--pn为x的所有质因数 就是要求这样的式子啦,不过求这条式子,相信有很多种方法可以求,这个不是难题: 不过问题是如何巧妙地求,如何简洁地写出代码. 直接硬求,或者求出质因数之后求都不是巧妙的方法了,参考了下别人的代码才知道可以写的这么巧妙的. 下面程序可以说是连消带打地求式子结果,分解质因子,可以如此简明地把解

POJ 2208 Pyramids 欧拉四面体

给出边长,直接就可以求出体积咯 关于欧拉四面体公式的推导及证明过程 2010-08-16 14:18 1,建议x,y,z直角坐标系.设A.B.C少拿点的坐标分别为(a1,b1,c1),(a2,b2,c2),(a3,b3,c3),四面体O-ABC的六条棱长分别为l,m,n,p,q,r: 2,四面体的体积为,由于现在不知道向量怎么打出来,我就插张图片了, 将这个式子平方后得到: 3,根据矢量数量积的坐标表达式及数量积的定义得 又根据余弦定理得 4,将上述的式子带入(1),就得到了传说中的欧拉四面体公

Dirichlet&#39;s Theorem on Arithmetic Progressions POJ - 3006 线性欧拉筛

题意 给出a d n    给出数列 a,a+d,a+2d,a+3d......a+kd 问第n个数是几 保证答案不溢出 直接线性筛模拟即可 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 bool Is_Primes[1000005]; 5 int Primes[1000005]; 6 int A[1000005]; 7 int cnt; 8 void Prime(int n){ 9 cnt=0; 1

Goldbach&#39;s Conjecture POJ - 2262 线性欧拉筛水题 哥德巴赫猜想

题意 哥德巴赫猜想:任一大于2的数都可以分为两个质数之和 给一个n 分成两个质数之和 线行筛打表即可 可以拿一个数组当桶标记一下a[i]  i这个数是不是素数  在线性筛后面加个装桶循环即可 #include<cstdio> #include<cstring> using namespace std; bool Is_Primes[1000005]; int Primes[1000005]; int cnt; void Prime(int n){ cnt=0; memset(Is_

POJ 2480 (约数+欧拉函数)

题目链接: http://poj.org/problem?id=2480 题目大意:求Σgcd(i,n). 解题思路: 如果i与n互质,gcd(i,n)=1,且总和=欧拉函数phi(n). 如果i与n不互质,那么只要枚举n的全部约数,对于一个约数d,必有gcd(i/d,n/d)互质,这部分的gcd和=d*欧拉函数phi(n/d). 不断累加暴力求解即可. 其实还可以公式化简,不过实在太繁琐了.可以参考金海峰神的解释. 由于要求好多欧拉函数,每次都分解质因数法必然TLE,这里所以采用O(√n)求单

POJ 1284-Primitive Roots(欧拉函数求原根)

Primitive Roots Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1284 Appoint description:  System Crawler  (2015-04-06) Description We say that integer x, 0 < x < p, is a primitive root mod

poj 1386 有向图欧拉(回)路

判断是否存在欧拉(回)路,注意先要用并查集判断图是否连通. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 26; 7 const int M = 1001; 8 int f[N]; 9 int degree[N]; 10 bool visit[N]; 11 char word[M]; 12 13 int fin

poj 3478 poj 3090(欧拉函数的应用)

3478题目意思是Farey序列是由一系列不能约分的分数a/b(0<a<b<=n且gcd(a,b)=1)按照递增的顺序组成的,然后给出了Fn的前几项,让你计算Fn中有多少个分数. 很明显Fn中的数的个数就是分别与(2,3,4.....n-1,n)互质的数的个数的和.也就是求欧拉函数的前n项和. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <st