Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5262 Accepted Submission(s): 1360
一个节点可以有K个子节点,问深度D最小是多少时,可以让这个深度的节点数mod p 之后等于N。
解题思路:
BSGS求离散对数!!!此题有坑,can't的上标是全角英文符号。。。。。而且因为是mod p之后等于N 所以N必须<P才可以有解。
AC代码:
#include <stdio.h> #include <string.h> #include <math.h> typedef long long LL; const int MAXN = 1000100; bool hash[MAXN]; LL var[MAXN]; LL p[MAXN]; void insert_x(LL n,LL v) { int x=v%MAXN; while(hash[x]&&var[x]!=v){ x++; if(x==MAXN) x=0; } if(!hash[x]){ p[x]=n; var[x]=v; hash[x]=true; } } LL find_x(LL v) { int x=v%MAXN; while(hash[x]&&var[x]!=v){ x++; if(x==MAXN) x=0; } if(hash[x]) return p[x]; return -1; } LL gcd(LL a,LL b) { if(b==0) return a; return gcd(b,a%b); } LL exgcd(LL a,LL b,LL &x,LL &y) { if(b==0){ x=1;y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return r; } LL BSGS(LL A,LL B,LL C) { LL n=1; for(int i=0;i<110;i++){ if(n==B%C) return i; n=n*A%C; } LL M=ceil(sqrt(C*1.0)); LL d=gcd(A,C); LL D=1; int cnt=0; while(d!=1){ if(B%d) return -1; B/=d; C/=d; D=D*A/d%C; d=gcd(A,C); cnt++; } LL res=1; for(int i=0;i<M;i++){ insert_x(i,res); res=res*A%C; } for(int i=0;i<M;i++){ LL x,y; LL r=exgcd(D,C,x,y); x=x*B; x=(x%C+C)%C; LL ans=find_x(x); if(ans!=-1) return i*M+ans+cnt; D=D*res%C; } return -1; } int main() { LL K,P,N; while(scanf("%lld%lld%lld",&K,&P,&N)!=EOF){ if(N>=P){ printf("Orz,I can’t find D!\n"); continue; } memset(hash,false,sizeof(hash)); memset(p,-1,sizeof(p)); memset(var,-1,sizeof(var)); LL res=BSGS(K,N,P); if(res==-1) printf("Orz,I can’t find D!\n"); else printf("%lld\n",res); } return 0; }