题目:http://codeforces.com/contest/604/problem/D
题意:给定p和k,p是大于2的素数。找满足的方案数,其中
.
例如p=3,k=2的方案数有三种:
- f(0) = 0, f(1) = 1, f(2) = 2.
- f(0) = 0, f(1) = 2, f(2) = 1.
- f(0) = f(1) = f(2) = 0.
分析:
当p=3,k=2时。
0*2%3=0;
1*2%3=2;
2*2%3=1;
可以发现0走一步回到0,1走两步回到1,2走两步回到2。
f(2*0%3)=2*f(0)%3=f(0)
f(2*1%3)=2*f(1)%3=f(2)
f(2*2%3)=2*f(2)%3=f(1)
可以发现0是自环,1和2形成环。
然后把所有的环都找到,由于环之间没有任何关系,根据乘法原理计数就好了。
现在的问题就是统计i走j步能回到的自己的数的种数。
for(LL i=0;i<p;i++)
{
LL temp=i;
for(LL j=1;j<=p;j++)
{
temp=temp*k%p;
if(temp==i)
{
// printf("i:%lld j:%lld\n",i,j);
num[j]++;
}
}
}
p^2打表会超时。
x*i^j%p=x;
就是找i^j%p=1;一个x满足的话,其他的数也会满足。
那么就是
LL temp=1;
for(LL i=1;i<p;i++)
{
temp=temp*k%p;
if(temp==1)
num[i]=p;
else
num[i]=1;
}
直接O(n)打表就好了。
Ps:注意k=0的情况。
代码:
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1e6+7;
const int mod = 1e9+7;
int k,p;
int fa[maxn];
int num[maxn];
void pro()
{
for(LL i=0;i<p;i++)
{
LL temp=i;
for(LL j=1;j<=p;j++)
{
temp=temp*k%p;
if(temp==i)
{
// printf("i:%lld j:%lld\n",i,j);
num[j]++;
}
}
}
}
void pro1()
{
LL temp=1;
for(LL i=1;i<p;i++)
{
temp=temp*k%p;
if(temp==1)
num[i]=p;
else
num[i]=1;
}
}
void getfa()
{
for(LL i=0;i<p;i++)
{
LL to=i*k%p;
fa[to]=i;
}
}
bool visit[maxn];
int main()
{
// freopen("t.txt","w",stdout);
int i,j;
while(cin>>p>>k)
{
if(k==0)
{
LL ret=1;
for(i=1;i<p;i++)
ret=ret*p%mod;
cout<<ret<<endl;
return 0;
}
memset(visit,0,sizeof(visit));
memset(num,0,sizeof(num));
pro1();
getfa();
LL ans=1;
for(i=0;i<p;i++) if(!visit[i])
{
int t=i;
int c=0;
while(!visit[fa[t]])
{
t=fa[t];
visit[t]=1;
c++;
}
ans=ans*num[c]%mod;
}
printf("%lld\n",ans);
}
return 0;
}