您的位置:首页 > 其它

hdu-3307 (欧拉定理+推导)

2017-08-20 18:44 260 查看
Problem Description
an = X*an-1 + Y and Y mod (X-1) = 0.
Your task is to calculate the smallest positive integer k that ak mod a0 = 0.

InputEach line will contain only three integers X, Y, a0 ( 1 < X < 231, 0 <= Y < 263, 0 < a0 < 231).OutputFor each case, output the answer in one line, if there is no such k, output "Impossible!".Sample Input2  0  9Sample Output1
题目题意:题目给你三个数x,y,a0 ,我们知道了一个等式,an=x*an-1+y 并且y mod x-1 ==0 让我们求一个最小的k使得ak % a0 =0.题目分析:我们首先对那个等式变一下形,高中数列基础比较好的话,对这样的式子比较敏感的。比较简单,为了方便,下面简单写了一下:


得到了这个式子,我们的题目是要让它为0,我们取B与a0的最大公约数gcd(B,a0),那么我们可以得到(x^n-1)*b%a0等价为(x^n-1)*(b%gcd)%(a0%gcd)因为(b%gcd)%(a0%gcd)肯定不会为0了,它们的最大公约数都没又来,不能在约了,所以要使得等式为0,只有使得(x^n-1)%(a0%gcd)==0,我们变一下形:x^n-1=k*(a0%gcd) x^n=k*(a0%gcd)+1左右模a0%gcd即 x^n=1%(a0%gcd)这个式子已经满足欧拉定理形式了。在数论中,欧拉定理,(也称费马-欧拉定理)是一个关于同余的性质。欧拉定理表明,若n,a为正整数,且n,a互质,则:

题目要找是最小的,那么就是phi
的因子。代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;

const int maxn=1e6+10;
int prime[maxn],cnt;
bool vis[maxn];
void get_prime()//素数打表
{
memset (vis,true,sizeof (vis));
vis[1]=false;
for (int i=2;i<maxn;i++) {
if (vis[i]) prime[cnt++]=i;
for (int j=i;j<cnt&&i*prime[j]<maxn;j++) {
vis[i*prime[j]]=false;
if (i%prime[j]==0) break;
}
}
}

ll gcd (ll a,ll b)
{
if (b==0) return a;
return gcd(b,a%b);
}

ll factor[100][2],fcnt;
void get_factor(ll n)//质因子分解
{
memset (factor,0,sizeof (factor));
fcnt=0;
for (int i=0;i<cnt&&prime[i]*prime[i]<=n;i++) {
if (n%prime[i]==0) {
factor[fcnt][0]=prime[i];
while (n%prime[i]==0) {
factor[fcnt][1]++;
n=n/prime[i];
}
fcnt++;
}
}
if (n!=1) {
factor[fcnt][0]=n;
factor[fcnt++][1]=1;
}
}

ll fast_pow(ll base,ll k,ll mod)//快速幂
{
ll ans=1;
while (k) {
if (k&1)
ans=ans*base%mod;
base=base*base%mod;
k>>=1;
}
return ans;
}
ll get_euler(ll n)
{
ll res=n,a=n;
for (ll i=2;i*i<=n;i++) {
if (a%i==0) {
res=res/i*(i-1);
while (a%i==0) a=a/i;
}
}
if (a>1)
res=res/a*(a-1);
return res;
}

int main()
{
get_prime();
ll x,y,a;
while (scanf("%lld%lld%lld",&x,&y,&a)!=EOF) {
y=y/(x-1);
ll gc=gcd (y,a);
a=a/gc;
if (gcd (a,x)!=1) {//不满足欧拉定理
printf("Impossible!\n");
continue;
}
ll phi=get_euler(a),ans;
get_factor(phi);
ans=phi;
for (int i=0;i<fcnt;i++) {
for (int j=0;j<factor[i][1];j++) {//把可以去掉的因子都去了,
if (fast_pow(x,ans/factor[i][0],a)==1) ans=ans/factor[i][0];
}
}
printf("%lld\n",ans);
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: