Acwing202. 最幸运的数字
题意:
现在给定一个正整数 L,请问至少多少个 8 连在一起组成的正整数(即最小幸运数字)是 L 的倍数。
题解:
x个8连在一起组成的正整数可写作8(10x−1)/98(10^x-1)/98(10x−1)/9。现在要求一个最小的x,满足L∣8(10x−1)9L|\frac{8(10^x-1)}{9}L∣98(10x−1).
L∣8(10x−1)9L|\frac{8(10^x-1)}{9}L∣98(10x−1)=9L∣8(10x−1)9L|8(10^x-1)9L∣8(10x−1)
我们设d=gcd(L,8)
有:gcd(L/d,8/d)=1
说明8/d与L/d互质
8(10^x-1)是9L的质数,有9Ld∣8d(10x−1)\frac{9L}{d}|\frac{8}{d}(10^x-1)d9L∣d8(10x−1)
因为8/d与L/d互质,所以9Ld∣(10x−1)\frac{9L}{d}|(10^x-1)d9L∣(10x−1)
再推导有:10x≡1(mod9Ld)10^x \equiv1 (\bmod \frac{9L}{d})10x≡1(modd9L)
引理:
若正整数a,n互质,则满足ax≡1(modn)a^x\equiv 1(\bmod n)ax≡1(modn)的最小正整数x0是ϕ(n)的约数\phi(n)的约数ϕ(n)的约数
所以我们只需要求出欧拉函数ϕ(9Ld)\phi(\frac{9L}{d})ϕ(d9L),枚举它的所有约数,用快速幂判断是否符合条件即可。时间复杂度是O(LlogL)O(\sqrt{L}\log{L})O(LlogL)
时间没问题,但是注意,你的longlong会被下面数据爆掉,所以要用到一个小技巧,叫龟速乘
1999999999
1213131311
1242342334
0
龟速乘其实就是把快速幂中乘法部分展开,将乘法转成加法做,每次运算都取mod,这样就不会爆
代码:
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...);
}
template <typename T> inline void write(T x)
{if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef LOCALstartTime= clock();freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef LOCALendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
ll mul(ll a, ll b, ll mod)
{ll ans= 0;while (b) {if (b & 1)ans= (ans + a) % mod;a= (a + a) % mod;b>>= 1;}return ans;
}
ll poww(ll a, ll b, ll mod)
{ll ans= 1;while (b) {if (b & 1)ans= mul(ans, a, mod) % mod;a= mul(a, a, mod) % mod;b>>= 1;}return ans % mod;
}
ll phi(ll n)
{ll ans= n;for (int i= 2; i <= sqrt(n); i++) {if (n % i == 0) {ans= ans / i * 1ll * (i - 1);while (n % i == 0)n/= i;}}if (n > 1)ans= ans / n * 1ll * (n - 1);return ans;
}
int main()
{//rd_test();ll l;int cas= 0;while (cin >> l) {if (l == 0)break;ll mod= l / __gcd(8ll, l) * 9ll;ll p= phi(mod);ll ret= 1e18;for (ll x= 1; x <= sqrt(p); x++) {if (p % x != 0)continue;if (poww(10, x, mod) == 1)ret= min(ret, x);if (poww(10, p / x, mod) == 1)ret= min(ret, p / x);}printf("Case %d: ", ++cas);printf("%lld\n", ret == 1e18 ? 0 : ret);}return 0;//Time_test();
}