题目链接:http://codeforces.com/contest/604/problem/D
题意:给定p ,k(p为奇质数)。一函数f(x)定义域和值域都为【0,p-1】,且满足f(k*i % p)==k*f(i)%p。问f(x)有多少种选择方式。
解法:
k==0时,只需满足f(0)==0,故ans=p^(p-1);
k==1时,f(x)==f(x),ans=p^p;
k>1时,有两种解法:
1.f(0)=0,对于其他的值,当f(x)确定时,f(k*x%p)也随之确定,f(k*k*x%p)也随之确定...相当于【1,p-1】被分为r个小环,确定每个环可以任选一个数字,ans=p^r。可以直接用dfs来实现。
2.(这种方法如何证明的不知道,留个坑)。r可以被(p-1)整除,即相当于找一个最小的len,使得(p-1)%len==0 && p^len%p==1,此时r=(p-1)/len。这种方法要快于上面的方法。
方法1的代码(31ms):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
using namespace std;
typedef long long LL;
const int mod = 1e9 +7;
LL fpow(LL x, int n){
LL ret = 1;
while (n){
if (n&1) ret = ret*x%mod;
x = x*x%mod;
n >>= 1;
}
return ret;
}
int mem[1000005];
void dfs(int x){
if(x==-1) return ;
int cur=mem[x];
mem[x]=-1;
dfs(cur);
}
int main (){
int p,k;
while(scanf("%d%d",&p,&k)!=EOF){
if(k<=1){
if(k==0) printf("%d\n",fpow(p,p-1));
else printf("%d\n",fpow(p,p));
continue ;
}
for(int i=0;i<p;i++)
mem[(LL)k*i%p]=i;
int cnt=0;
for(int i=1;i<p;i++)
if(mem[i]!=-1){
cnt++;
dfs(i);
}
printf("%d\n",fpow(p,cnt));
}
return 0;
}
方法2(15ms):
#include <stdio.h>
#include <stdlib.h>
#define MOD 1e9 + 7
long long power(long long a, long long b, long long m) {
long long c = 1;
for(; b; b >>= 1) {
if(b & 1) {
c = (c * a) % m;
}
a = (a * a) % m;
}
return c;
}
long long solve(long long p, long long k) {
long long ord, i;
switch(k) {
case 0:
return power(p, p-1, MOD);
case 1:
return power(p, p, MOD);
}
ord = p - 1;
for(i = 2; i < ord; i++) {
if(ord % i == 0) {
if(power(k, ord / i, p) == 1) {
ord = ord / i;
i--;
}
}
}
return power(p, (p - 1) / ord, MOD);
}
int main() {
long long p, k;
scanf("%I64d%I64d", &p, &k);
printf("%I64d\n", solve(p, k));
return 0;
}