• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
MZQ667
博客园    首页    新随笔    联系   管理    订阅  订阅

[luogu] P4861 按钮

[luogu] P4861 按钮


1.题目

题目背景

\(Ada\)被关在了一个房间里。

题目描述

房间的铁门上有一个按钮,还有一个显示屏显示着“1”。

旁边还有一行小字:“这是一个高精度\(M\)进制计算器,每按一次按钮,屏幕上的数便会乘以\(K\)。当个位数再次变为\(1\)时,门就开了。”

由于\(Ada\)急于出去,所以你要在\(1s\)之内求出她的最小按键次数。

输入输出格式

输入格式:

一行,两个整数\(M\)和\(K\)。

输出格式:

一行一个数字,表示最小按键次数。
如果无论\(Ada\)按多少次都无法让门打开,输出"Let's go Blue Jays!"(不含引号)。

输入输出样例

输入样例#1:

11 2

输出样例#1:

10

输入样例#2:

6 26

输出样例#2:

Let's go Blue Jays!

说明

对于\(30\%\)的数据,\(2 \leqslant M,K \leqslant 10^4\)。

对于\(100\%\)的数据,\(2 \leqslant M,K \leqslant 2×10^9\)。

\(Update\):我们不认为个位为11,21,...为问题的解(例如,11在16进制下记为B)

2.题解

数竟出的题真恐怖

30pts

可以开一个\(unordered_map\)判重,然后模拟乘的过程。

不用想,对是对,但是你280ms过是不存在的。

100pts

考虑求\(K^r \equiv 1 (mod~M)\)最小解( \(r\) 在数论中称作阶)。此方程有解当且仅当\(gcd(K, M) = 1\)。

假设所求方程中\(gcd(K, M) = 1\),则由欧拉定理得\(K^{\phi(M)} \equiv 1(mod~M)\)。但\(\phi(M)\)不一定是最小的\(r\)。

阶有一个善良的性质,即\(r | \phi(M)\)。这样我们可以\(O(\sqrt{\phi(M)})\)枚举因子,然后求可以使方程成立的因子的最小值即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
typedef long long ll;
ll k, m, ans(0x7ffffffffffff), a(1);
using std::swap; using std::exit; using std::min;
inline ll gcd(ll a, ll b){
    if(a < b) swap(a, b);
    return (!(b) ? a : gcd(b, a % b)); 
}
inline ll euler_phi(ll x) {
    ll ans(x), tmp(x);
    ll xx = ll(ceill(sqrtl((long double)x)));
    for (ll i = 2; i <= xx; ++i) 
        if(!(tmp % i)) {
            ans = ans / i * (i - 1);
            while(!(tmp % i)) tmp /= i;
        }
    if(tmp > 1) ans = ans / tmp * (tmp - 1);
    return ans;
}
inline ll f_pow(ll a, ll b) {
    ll base(a), ans(1);
    while(b) {
        if(b & 1) ans = (ans * base) % m;
        base = (base * base) % m;
        b >>= 1;
    }
    return ans;
}
int main() {
    scanf("%lld%lld", &m, &k);
    if(gcd(m, k) != 1) {puts("Let's go Blue Jays!"); exit(0);}
    ll phi = euler_phi(m);
    ll p = ll(ceill(sqrtl((long double)phi)));
    for (ll i = 1; i <= p; ++i)
        if(!(phi % i)) {
            (f_pow(k, i) == 1) ? ans = min(ans, i) : false;
            (f_pow(k, phi / i) == 1) ? ans = min(ans, phi / i) : false;
        }
    printf("%lld\n", ans);
    return 0;
}
知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
posted @ 2018-10-30 07:46  mzq667  阅读(233)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3