cf #334 D. Moodular Arithmetic (组合计数)

来源:互联网 发布:sony vegas mac破解版 编辑:程序博客网 时间:2024/06/18 11:47

题目:http://codeforces.com/contest/604/problem/D

题意:给定p和k,p是大于2的素数。找满足的方案数,其中.

例如p=3,k=2的方案数有三种:

  1. f(0) = 0f(1) = 1f(2) = 2.
  2. f(0) = 0f(1) = 2f(2) = 1.
  3. 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形成环。

这个题目就是让你先找一个f(t)作为起点,看走几步回到f(t),然后找走这么多步数能回到自己的数有多少种。那么这个环的可能情况就是这个种数。
然后把所有的环都找到,由于环之间没有任何关系,根据乘法原理计数就好了。

现在的问题就是统计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;elsenum[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;elsenum[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;}

0 0