这是很明显的数论题,求10模某数的阶.(要构造的数是8*(10 ^ n - 1) / 9, 所以是求10)
题目链接:http://acm.ustc.edu.cn/ustcoj/problem.php?id=1106
注意到一些特殊小情况,其余直接求阶,一是10有因子5,所以,设幸运数是l, l能被5整除则不能被构造,另外,要构造的数中2的次数最多3次,所以模16等于0一概不能被构造,
最后要注意表达式除以9,所以我们最好回避l有因子三的情况,一旦有因子3,除尽为止,保存到另外一个数上, 因为两个互质的数相乘,然后求10关于他们积的阶,等于10关于各自阶的最小公倍数,所以这样把因子三分开处理即可.
由欧拉定理, 如果(10, l) = 1, 10 ^ Eulor(l) mod(l) = 1;
所以需要Eulor函数,但Eulor(l)不一定是阶,所以需要求Eulor(l)的因子,需要求一个数所有因子的函数,
另外Eulor(l)可以很大,求10的Eulor(l)次幂时,需要快速幂算法.
于是写出如下代码;
#include<cstdio>
#include<iostream>
using namespace std;
int gcd(int p, int q)
{
int t;
while (q)
{
t = q;
q = p % q;
p = t;
}
return p;
}
int qpow(int m, int n, int mod)
{
long long re = 1, tem = m;
while (n)
{
if (n & 1)
{
re *= tem;
re %= mod;
}
tem *= tem;
tem %= mod;
n >>= 1;
}
return re;
}
int euler(int n)
{
int res = n, a = n;
for(int i = 2; i * i <= a; i++)
{
if(a % i == 0)
{
res = res / i * (i - 1);
while(a % i == 0)
a /= i;
}
}
if(a > 1)
res = res / a * (a - 1);
return res;
}
void factor(int n, int *f, int *l)
{
int i, j;
for (i = 1, j = 0; i * i <= n; ++i)
{
if (n % i == 0)
{
f[j++] = i;
f[j++] = n / i;
}
}
*l = j;
}
int re(int luck)
{
int i, len, f[1000] = {0}, l, min = -1;
while (luck % 2 == 0)
luck >>= 1;
l = euler(luck);
if (l == 1)
return 1;
factor(l, f, &len);
for (i = 1; i < len; ++i)
{
if (qpow(10, f[i], luck) == 1)
min = min < f[i] && min > 0 ? min : f[i];
}
return min;
}
int main()
{
int n = 1, luck, f3, tem1, tem2, res = 0;
while (scanf("%d", &luck), luck)
{
f3 = 9;
if (luck % 5 == 0 || luck % 16 == 0)
printf("Case %d: 0\n", n++);
else
{
if(luck % 3 == 0)
{
while (luck % 3 == 0)
{
f3 *= 3;
luck /= 3;
}
tem1 = re(luck);
tem2 = re(f3);
res = tem1 * tem2 / gcd(tem1, tem2);
printf("Case %d: %d\n", n++, res);
}
else
{
res = re(luck);
printf("Case %d: %d\n", n++, res);
}
}
}
return 0;
}
一些说明:
gcd是为了求最小公倍数;因为lcm (x,y)= x*y / gcd(x,y);
快速幂只需要知道模的结果,所以加了参数mod;
过程中为了防止数据溢出,用long long(不用long long会溢出, 比如1111111113)
factor函数把因子保存在f[1000]中,1000是经过尝试的值一开始估计50000,但事实上2000000000以下的数因子个数最多不超过1000,并把数组中存放了的因子个数信息也返回了.
逐个尝试因子是否模余一, 幷取最小的因子即可.
最后:
这是一道比较令我满意的题目,代码效率较高,比之前AC的最快代码快了一倍吧.
很喜欢数论.^_^