题目大意:对于给定的整数L,找出L能整除最短的全8序列的长度,做为Bob的幸运数字。
解析:一开始做这个题的时候直接莽夫式做法 ,枚举8的位数,交一发直接wa,想想也是,没给8的位数的上限,暴力枚举8的话肯定要爆longlong的。 。。
正确的做法居然是用欧拉定理。我们可以通过题意列出下式:8/9 * (10^x-1)=L * p
根据欧拉定理我们知道:10^Φ(m)≡1(mod m)。 我们要做的就是把根据题目推出来的式子化成欧拉定理的式子(这个具体的推导过程真的没想出来,参考了大神的博客才懂:戳这里) 具体就不赘述了,代码描述的还是很清楚的。
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
struct node{
ll cnt;
ll p;
};
node num[100];
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll Euler(ll n){//欧拉函数
ll ret=1,i;
for(i=2;i*i<=n;i++){
if(n%i==0){
n/=i;ret*=i-1;
while(n%i==0){
n/=i;ret*=i;
}
}
}
if(n>1)ret*=n-1;
return ret;
}
ll solve(ll n){//基本算数定理 用num记录下n由那些素数组成,这些素数分别有几个
int t=0;
for(ll i=2;i*i<n;i++){
if(n%i==0){
num[t].p=i;
num[t].cnt=0;
while(n%i==0){
num[t].cnt++;
n/=i;
}
t++;
}
}
if(n>1){
num[t].p=n;
num[t].cnt=1;
t++;
}
return t;//返回素数的种类
}
ll multi(ll a,ll b,ll c) {//由于爆int 所以用的快速乘法和快速幂
ll ans = 0;
while (b) {
if (b & 1) {
ans += a;ans %= c;
}
a += a;a %= c;
b >>= 1;
}
return ans;
}
ll Pow(ll a, ll b, ll c) {
ll ans = 1;
while (b) {
if (b & 1) {
ans = multi(ans, a, c);
}
a = multi(a, a, c);
b >>= 1;
}
return ans;
}
int main(){
ll L;
int ca=1;
while(cin>>L,L){
ll m=9*L/gcd(L,8);
if(gcd(10,m)!=1){
printf("Case %d: 0\n",ca++);
continue;
}
ll pi=Euler(m);
ll cnt=solve(pi);
for(int i=0;i<cnt;i++){//缩小pi,找到满足条件的最小的pi
for(int j=0;j<num[i].cnt;j++){
if(Pow(10,pi/num[i].p,m)==1){
pi/=num[i].p;
}
}
}
printf("Case %d: %lld\n",ca++,pi);
}
return 0;
}