hdu 2462 数学欧拉 The Luckiest number

题目思路:
求解10^x = 1 (mod 9*L/gcd(L,8))的满足x>0的最小解就是答案
由8构成的数A设有x位
那么A=8(10^0+10^1+...+10^(x-1));
很容易得到A=(8/9)*(10^x-1);
题目的要求就是A=0(mod L)
就是(8/9)*(10^x-1)=0(mod L);
->8*(10^x-1)=0(mod 9L);
-> 10^x-1=0(mod 9L/gcd(L,8));
->10^x =1 (mod 9L/gcd(L,8));
令p=9*L/gcd(L,i), 等价于10^x==1(mod p),求满足条件的最小的整数x
看到这个式子,我们的第一反应就是数论书上的Euler定理,但是如果gcd(10,p)!=1,即不互素,也就是不满足欧拉定理的条件了,所以此时为no answer.
if(gcd(10,p)==1) 满足欧拉定理, 我们知道10^oula(p)==1(mod p)肯定是满足的;

虽然oula(p)满足上述同余方程,但题目求是最小x,而oula(p)未必是最小的解。考虑到oula(p)不是素数,所以我们就要将oula(p)因子分解,求出oula(p)所有的因子,然后逐个从小到大枚举,如果满足10^x==1(mod p) (其中x为oula(p)的因子),x即为答案。


这题除了思路是思路之外,就是模板题了。。。

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#define LL long long
#define nmax 134165
#define nnum 13000
#define num8 8
#define num9 9
#define num10 10
int flag[nmax], prime[nnum], cpfactor[nnum];
LL pfactor[nnum], factor[nnum];
int plen, len_pfactor, len_factor;
void mkprime(){
    int i,j;
    memset(flag,-1,sizeof(flag));
    for(i = 2, plen = 0; i < nmax; i ++){
        if(flag[i])
            prime[plen ++] = i;
        for(j = 0; (j < plen) && (i * prime[j] < nmax); j ++){
            flag[ i * prime[j] ] = 0;
            if(i % prime[j] == 0)
                break;
        }
    }
}
int cmp(const void *a, const void *b) {
    LL temp = *(LL *) a - *(LL *) b;
    if (temp > 0) {
        return 1;
    } else if (temp < 0) {
        return -1;
    }
    return 0;
}
LL getPhi(LL n) {//求欧拉函数的值
    int i, te;
    LL phi;
    te = (int) sqrt(n * 1.0);
    for (i = 0, phi = n; (i < plen) && (prime[i] <= te); i++) {
        if (n % prime[i] == 0) {
            phi = phi / prime[i] * (prime[i] - 1);
            while (n % prime[i] == 0) {
                n /= prime[i];
            }
        }
    }
    if (n > 1) {
        phi = phi / n * (n - 1);
    }
    return phi;
}
LL modular_multi(LL a, LL b, LL c) {// a * b % c
    LL res, temp;
    res = 0, temp = a % c;
    while (b) {
        if (b & 1) {
            res += temp;
            if (res >= c) {
                res -= c;
            }
        }
        temp <<= 1;
        if (temp >= c) {
            temp -= c;
        }
        b >>= 1;
    }
    return res;
}
LL modular_exp(LL a, LL b, LL c) { //a ^ b % c 改成mod_pow就不行,中间发生了溢出,还是这个模板靠谱
    LL res, temp;
    res = 1 % c, temp = a % c;
    while (b) {
        if (b & 1) {
            res = modular_multi(res, temp, c);
        }
        temp = modular_multi(temp, temp, c);
        b >>= 1;
    }
    return res;
}
LL gcd(LL a,LL b){
    if(a < b)
        a ^= b, b ^= a, a ^= b;
    if(b == 0)
        return a;
    if(!(a & 1) && !(b & 1))
        return gcd(a >> 1, b >> 1) << 1;
    else if(!(b & 1))
        return gcd(a,b >> 1);
    else if(!(a & 1))
        return gcd(a >> 1,b);
    else
        return gcd(b,a - b);
}
void findpFactor(LL n) {
    int i, te, cnt;
    te = (int) sqrt(n * 1.0);
    for (i = 0, len_pfactor = 0; (i < plen) && (prime[i] <= te); i++) {
        if (n % prime[i] == 0) {
            cnt = 0;
            while (n % prime[i] == 0) {
                cnt++;
                n /= prime[i];
            }
            pfactor[len_pfactor] = prime[i];//有谁
            cpfactor[len_pfactor++] = cnt;//有几个
        }
    }
    if (n > 1) {
        pfactor[len_pfactor] = n;
        cpfactor[len_pfactor++] = 1;
    }
}
void dfs(int k, LL now) {//求所有质因数的乘积
    if (k == len_pfactor) {
        factor[len_factor++] = now;
        return;
    }
    int i;
    for (i = 0; i < cpfactor[k]; i++) {
        now = now * pfactor[k];
        dfs(k + 1, now);
    }
    for (i = 0; i < cpfactor[k]; i++) {
        now = now / pfactor[k];
    }
    dfs(k + 1, now);
}
void solve(int n) {
    int i, d;
    LL c, phi;
    d = gcd(n, num8);
    c = (LL) n;
    c = c / d * num9;//先除再乘
    if (gcd(num10, c) != 1) {//如果和10不互素
        puts("0");//则答案不存在
        return;
    }
    phi = getPhi(c);
    findpFactor(phi);
    len_factor = 0;
    dfs(0, 1);//得到所有phi的因子相乘小于等于phi的乘积
    qsort(factor, len_factor, sizeof(factor[0]), cmp);
    for (i = 0; i < len_factor; i++) {
        if (modular_exp(num10, factor[i], c) == 1) {
            printf("%I64d\n", factor[i]);
            return;
        }
    }
}
#include <iostream>
using namespace std;
int main() {
    int n, cas;
    mkprime();
    cas = 0;
    while (~scanf("%d", &n) && n) {
        printf("Case %d: ", ++cas);
        solve(n);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值