51nod-1359: 循环探求
【传送门:51nod-1359】
简要题意:
给出n和k,求出最小的x满足$n^{x}≡n(mod\;10^{k})$
题解:
真是一道有(du)趣(liu)题目
首先我们设X[k-1]为$n^{x}≡n(mod\;10^{k-1})$成立的最小的x
那么我们就可以得到$n^{X[k-1]}≡n(mod\;10^{k-1})$
设$N[k-1]=n^{X[k-1]}$
设t为任意值,可以发现$n^{t*X[k-1]}≡N[k-1]^{t}(mod\;10^{k-1})$
假设t*X[k-1]为满足$n^{x}≡n(mod\;10^{k})$的最小的x的话,其实可以知道变的只有第k位,而第1到第k-1位仍然是不变的,那么我们对于一个k就枚举t,因为抽屉原理,所以N[k-1]^t的第k位最多只有10种情况,t枚举到12都仍未找到则说明不存在x,就直接输出1
否则将得到的t连乘,最后+1就是答案了
PS:为了不超时,高精度的时候要控制长度在k以内,不会影响结果
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; struct node { int a[2100],len; node() { len=0; memset(a,0,sizeof(a)); } }N,d; char st[610];int k; node multi(node n1,node n2) { node no;no.len=k; for(int i=1;i<=k;i++) { for(int j=1;j+i-1<=k;j++) no.a[i+j-1]+=n1.a[i]*n2.a[j]; } for(int i=1;i<=no.len;i++) { no.a[i+1]+=no.a[i]/10; no.a[i]%=10; } return no; } node solve(node n1,int n2) { node no;no.len=n1.len; for(int i=1;i<=no.len;i++) no.a[i]=n1.a[i]*n2; for(int i=1;i<=no.len;i++) { no.a[i+1]+=no.a[i]/10; no.a[i]%=10; } int i=no.len; while(no.a[i+1]>0) { i++; no.a[i+1]+=no.a[i]/10; no.a[i]%=10; } no.len=i; return no; } int main() { scanf("%s%d",st+1,&k); int len=strlen(st+1);N.len=len; for(int i=1;i<=len;i++) N.a[i]=st[len-i+1]-'0'; d.a[1]=1;d.len=1; node B=N,p,x; for(int i=1;i<=k;i++) { int t=1; x=B; while(t<=11) { p=multi(N,B); if(p.a[i]==N.a[i]) break; B=multi(B,x);t++; } if(t>11){printf("1\n");return 0;} d=solve(d,t); } d.a[1]++; for(int i=1;i<=d.len;i++) { d.a[i+1]+=d.a[i]/10; d.a[i]%=10; } int i=d.len; while(d.a[i+1]>0) { i++; d.a[i+1]+=d.a[i]/10; d.a[i]%=10; } d.len=i; for(int i=d.len;i>=1;i--) printf("%d",d.a[i]); printf("\n"); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚