您的位置:首页 > 其它

poj3696 The Luckiest number By Assassin

2017-04-26 23:19 288 查看
本题真是一道好题,被坑了一晚上才做出来…

题目大意:给定一个数组L,求是否存在形如8888…888的数字可以被L整除。如果有求最短的。

一开始拿到题目真的是不知所以然…直到最后也是参考别人的思路,不过毕竟队伍中数学题的锅不是我背的~哈哈~用的是信息安全数学上面的知识,下面见分析。

分析:

首先我们假设形如888888的数字可以拆分如下:

1.8*(111…1111)=mL(其中m我们是不知道的,L是给定值,并且我们现在假设存在等式成立)

2.进一步变化可以得到 :

8*(10^k-1)/9=mL

8*(10^k-1)=9mL

3.假定d=gcd(8,L);定义p=8/d、q=9L/d,这个时候易得p和q互质这个时候式子的形式如下p*(10^k-1)=mq

4.因为p和q互质,那么一定有(10^k-1)%q==0,即10^k==1 modp

5.假设gcd(10,q)==1,根据欧拉函数可得一定存在10^phi(q)==1 mod p,当然如果gcd(10,q)!=1根本不存在上述情况,等式不成立,这个时候输出0

6.再次根据欧拉定理性质,虽然phi(q)可以是10的阶数,但是不一定是最小的!那么我们还要找更小的值!而且可能的答案一定是phi(q)的因数。

下面讲一下坑点:

1.首先是根本不知道数据规模会是什么样子,尤其是看着第六步多个素数组合数,用dfs真的没超时???也是谢天谢地了,让我写多少不太敢用

2.这里L实在是太大了,大到得到的q可能也很大,这个时候就存在long long乘法都爆炸的情况,所以乘法函数也得自己写 !凸(艹皿艹 )

3.在我们去phi(q)的人家有现成的公式啊

(1). 将n表示成素数的乘积: n = p1 ^ k1 * p2 ^ k2 * … * pn ^kn(这里p1, p2, …, pn是素数)

(2). PHI(n) = (p1 ^ k1 - p1 ^ (k1 - 1)) * (p2 ^ k2 - p2 ^ (k2 - 1)) * … * (pn ^ kn - pn ^ (kn - 1))

=n*(p1-1)(p2-1)……(pi-1)/(p1*p2*……pi);

=n*(1-1/p1)*(1-1/p2)….(1-1/pn)

我的丑代码

#include<bits/stdc++.h>
using namespace std;
long long  value[100050],times[100050],tnum,lll;    //拆分素数的值,出现次数
long long d,p,q,phi;
long long answer[10000],anspos;                     //求phi(q)因数的存储空间

long long multi(long long a,long long b,long long mod){         //自己写的乘法公式
long long  result=0;
while(b){
if(b&1) result+=a;
if(result>=mod) result-=mod;
a=a+a;
if(a>=mod) a-=mod;
b>>=1;
}
return result;
}
long long quickmod(long long a,long long b,long long m){        //快速幂取模的模板
long long ans = 1;
while(b){
if(b&1)
{
ans = multi(ans,a,m);
b--;
}
b/=2;
a = multi(a,a,m);
}
return ans;
}
long long  check(long long n,long long mod){            //检测是否满足最终的验证
if(quickmod(10,n,mod)==1) return 1;
else return 0;
}

long long gcd(long long a,long long b){
if(a%b==0) return b;
return gcd(b,a%b);
}
void apart(long long l){            //将大数拆成素数的乘积
tnum=1;
for(long long i=2;i*i<=l;i++){
if(l%i==0){
value[tnum]=i;
times[tnum]=1;
l/=i;
while(l%i==0){
times[tnum]++;
l/=i;
}
tnum++;
}
}
if(l>1){
value[tnum]=l;
times[tnum]=1;
tnum++;
}
}

void dfs(long long v,int t){            //dfs(求phi的因数)
if(t==tnum){
answer[++anspos]=v;
return ;
}
dfs(v,t+1);
for(int i=1;i<=times[t];i++){
v*=value[t];
dfs(v,t+1);
}
}

long long  getphi(long long n)          //这里phi(q)是有公式的
{
long long ans=1,i;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
n/=i;
ans*=i-1;
while(n%i==0)
{
n/=i;ans*=i;
}
}
}
if(n>1)
ans*=n-1;
return ans;
}
int main(){
//freopen("input.txt","r",stdin);
int T=0;
while(scanf("%lld",&lll)&&lll){
anspos=0;
d=gcd(8,lll);
p=8/d;
q=9*lll/d;
d=gcd(10,q);
if(d!=1){
printf("Case %d: 0\n",++T);
continue;
}
phi=getphi(q);
apart(phi);
dfs(1,1);
sort(answer+1,answer+anspos+1);
for(int i=1;i<=anspos;i++){
if(check(answer[i],q)){
printf("Case %d: %lld\n",++T,answer[i]);
break;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: