您的位置:首页 > 其它

poj3696 快速幂的优化+欧拉函数+gcd的优化+互质

2015-03-05 19:28 253 查看
这题满满的黑科技orz

题意:给出L,要求求出最小的全部由8组成的数(eg: 8,88,888,8888,88888,.......),且这个数是L的倍数

sol:全部由8组成的数可以这样表示:((10^x)-1)*(8/9)

那么有m=((10^x)-1)*(8/9)=k*L,answer即满足条件的最小的x

性质1:若ax=by且a和b互质,那么说明a中没有任何b的质因子,b的质因子一定都在x里。所以x是b的倍数。

所以先想方设法在等式中构造两个互质的数以便化简。我们取p=8/gcd(8,L),q=9*L/gcd(8,L)

那么有p*((10^x)-1)=q*k,且p与q互质【8/gcd(8,L)与L/gcd(8,L)一定互质。8又没有3这个质因子,所以9*L/gcd(8,L)还是会互质】

所以由性质1,(10^x)-1是q的倍数。

所以(10^x)-1=0  (mod q)

  (10^x)=1  (mod q)

性质2:欧拉定理。对于正整数a,n,若gcd(a,q)=1,则有a^phi(q)=1  (mod q)    【其中phi是欧拉函数】

这个式子是不是和上面很像呢~

所以若gcd(10,q)=1说明有解,否则无解

对于有解的情况,x=phi(q)就是一个解,但不一定是最小解。actually,0---phi(q)中还可能存在解。

性质3:因为后面有mod n,而余数都是有循环节的。(即一个循环周期的长度,设为r)

eg:如果有10^a=1 (mod q),那么10^(a+r)=1 (mod q)

首先x=0是一个解【10^0=1 (mod q)】。而且已经确定phi(q)也是一个解了。所以phi(q)一定是这个循环节r的倍数。

根据性质3,r肯定也是一个解。而且是最小的。

所以只要枚举phi(q)的约数,找出其中最小的满足条件的即可。

-----------------------接下来是满满的黑科技orz----------------------

Q1:本题数据很大,求gcd的过程会TLE肿么办

A1:因为gcd里面有一个数字是固定的,所以可以用一下黑科技

//q=9*N/gcd(8,N);
q=9*N;
for (int i=0;i<3;i++)
if (q%2==0)
q=q/2;
else break;
要求的是q/gcd(8,N)
而8分解质因数之后是2^3,也就是说带8的gcd里面最多也只可能有3个2。所以直接把这3个2能除掉的都除掉就行了


//if (gcd(10,q)!=1)    ans=0;
if  ((q%2==0)||(q%5==0))
ans=0;
10的质因子只有2和5。如果q是2或5的倍数,就说明q和10不互质。


Q2:求快速幂取模(10^x)%q的时候,数据超了long long的范围,会出错

A2:这样:

LL func(LL a,LL b,LL c)     //a*b%c
{
long long ret = 0;
while (b)
{
if (b & 1)
ret = (ret + a) % c;
a = 2 * a % c;
b >>= 1;
}
return ret;
}

LL pow_mod(LL a,LL b,LL MOD)
{
if (a==1)   return 1;
LL t=a%MOD,ans=1;
while(b)
{
if (b&1)
ans=func(ans,t,MOD);
t=func(t,t,MOD);
b>>=1;
}
return ans;
}


其实我也没看懂func是个什么鬼。。。。【逃

AC Code:

 #include <iostream>
#include <cstdio>
using namespace std;
#define LL long long
#define MAXL 1000

LL TC=0;
LL N,MOD,TM,q,ans;
int phi[MAXL+5];

int gcd(int a,int b) //辗转相除法,返回gcd(a,b)
{
if (b==0) return a;
return gcd(b,a%b);
}

long long euler(long long n)
{
long long ret = n;
for (long long i = 2; i * i <= n; i++)
if (n % i == 0)
{
ret = ret / i * (i - 1);
while (n % i == 0)
n /= i;
}
if (n > 1)
ret = ret / n * (n - 1);
return ret;
}

/*
LL pow_mod(LL a,LL b,LL MOD)
{
if (a==1) return 1;
LL t=a%MOD,ans=1;
while(b)
{
if (b&1)
ans=ans*t%MOD;
t=t*t%MOD;
b>>=1;
}
return ans;
}
*/

LL func(LL a,LL b,LL c) //a*b%c { long long ret = 0; while (b) { if (b & 1) ret = (ret + a) % c; a = 2 * a % c; b >>= 1; } return ret; } LL pow_mod(LL a,LL b,LL MOD) { if (a==1) return 1; LL t=a%MOD,ans=1; while(b) { if (b&1) ans=func(ans,t,MOD); t=func(t,t,MOD); b>>=1; } return ans; }

int main()
{
//calc_phi(MAXL);
while (~scanf("%I64d",&N))
{
TC++;
if (N==0) break;
//q=9*N/gcd(8,N);
q=9*N;
for (int i=0;i<3;i++)
if (q%2==0)
q=q/2;
else break;

TM=euler(q); //tm=phi[q];
ans=TM;
//if (gcd(10,q)!=1)
if ((q%2==0)||(q%5==0))
ans=0;
else
{
for (LL i=1; i*i<=TM; i++)
if (TM%i==0)
{
LL t1=i,t2=TM/i;
LL M1=pow_mod(10,t1,q);
LL M2=pow_mod(10,t2,q);
//cout<<t1<<" "<<M1<<endl<<t2<<" "<<M2<<endl;
if ((M1==1)&&(t1<ans))
ans=t1;
if ((M2==1)&&(t2<ans))
ans=t2;
}
}
printf("Case %d: ",TC);
cout<<ans<<endl;
}
}

/*
LL len,tmp,N;
int TC=0;
bool ok;

int main()
{
while(~scanf("%I64d",&N))
{
TC++;
if (N==0) break;
tmp=8;
len=1;
ok=false;
if (tmp%N==0) ok=true;
while ((!ok)&&(len<=MAXL))
{
tmp=tmp*10+8;
len++;
if (tmp%N==0)
ok=true;
}
if (ok)
printf("Case %d: %I64d\n",TC,len);
else
printf("Case %d: 0\n",TC);
}

return 0;
}
*/


View Code

Reference:
http://www.cnblogs.com/rainydays/archive/2012/11/05/2754760.html http://blog.csdn.net/yhrun/article/details/6908470
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: