AC通道:http://codeforces.com/problemset/problem/303/D
【题目描述】
Bike是一位机智的少年,非常喜欢数学。他受到142857的启发,发明了一种叫做“循环数”的数。
如你所见,142857是一个神奇的数字,因为它的所有循环排列能由它乘以1,2,...,6(1到它的长度)得到。循环排列意味着将该数的一些数位从尾部挪到前面。例如,12345的循环排列包括:12345,51234,45123,34512,23451.值得一提的是,允许出现前导零。因此4500123和0123450都是0012345的循环排列。你可以看到142857满足条件的原因。以下六个等式是在十进制下的。
·142857*1=142857
·142857*2=285714
·142857*3=428571
·142857*4=571428
·142857*5=714285
·142857*6=857142
现在Bike有一个问题。他将“循环数”扩展到任意进制b。如前所述,142857是十进制下的循环数。另一个例子是二进制下的0011.以下四个等式是二进制的:
·0011*1=0011
·0011*10=0110
·0011*11=1001
·0011*100=1100
他想要找出最大的b(1<b<x)使得有一个b进制下长度为n的正循环数(允许前导零)。
注意,当你将循环数乘以1到其长度的任意整数时你都应该得到一个它的循环排列。
【题解】
传送门:http://blog.youkuaiyun.com/wmdcstdio/article/details/45042353?locationNum=7
%%%%%%%%%%%%王梦迪大神
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 5000010
#define FILE "read"
typedef long long ll;
ll n,x,cnt,len,pr[MAXN],prime[MAXN],isprime[MAXN];
ll gcd(ll a,ll b) {return !b?a:gcd(b,a%b);}
ll fast(ll a,ll b,ll mod) {ll sum=1;for(;b;b>>=1,a=a*a%mod)if(b&1)sum=sum*a%mod;return sum;}
inline ll read()
{
ll x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void get()
{
for(ll i=2;i<=MAXN-10;i++)
{
if(!isprime[i]) prime[++cnt]=i;
for(ll j=1;j<=cnt&&prime[j]*i<=MAXN-10;j++)
{
isprime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
void pre(ll p)
{
ll temp=p-1;
for(ll i=1;i<=cnt;i++)
{
if(temp%prime[i]==0) pr[++len]=prime[i];
while(temp%prime[i]==0) temp/=prime[i];
}
if(temp>1) pr[++len]=temp;
}
bool check(ll d,ll p)
{
if(gcd(p,d)!=1) return 0;
for(ll i=1;i<=len;i++) if(fast(d,(p-1)/(pr[i]),p)==1) return 0;
return 1;
}
int main()
{
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); x=read();
get();
if(isprime[n+1]) {printf("-1\n"); return 0;}
pre(n+1);
for(ll i=x-1;i>1;i--) if(check(i,n+1)) {printf("%I64d\n",i); return 0;}
printf("-1\n");
return 0;
}