码蹄集 - MT3111· 赋值

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了码蹄集 - MT3111· 赋值相关的知识,希望对你有一定的参考价值。

传送门


赋值

时间限制:1秒
空间限制:64M


题目描述

冒险团正在一座奇妙秘境探险,眼前正是秘境的奖励关,关卡机制如下:随机给定M个金币,如果能找到三个不大于M的正整数(可以相同),求得它们的最小公倍数S,那么冒险团就可以获得S枚金币。为了得到最多的金币,大家一致决定将这项求解任务交给你这位团队智囊,求出S的最大值。


输入描述

输入一个正整数n

  • 1<=n<=1e6

输出描述

输出题意中三个数的最小公倍数S的最大值


样例一

输入

10

输出

630

题目分析

这道题题目可以概括为:求从 1 ∼ n 1\\sim n 1n中任选出三个数的最小公倍数的最大值。

这道题其实就是数学问题。想要暴力地枚举三个数的复杂度是 O ( n 3 ) O(n^3) O(n3),肯定会超时。

所以我们就需要用到互质的数学性质。以下结论可能未证明,但是不影响通过本题。

很明显,当三个数互质的时候,三个数的最小公倍数最大。

方法一:数学公式

  • n n n为奇数时, n n n n − 1 n-1 n1 n − 2 n-2 n2互质
  • n n n为偶数时
    • n n n能被 3 3 3整除时, n − 1 n-1 n1 n − 2 n-2 n2 n − 3 n-3 n3互质
    • n n n不能被 3 3 3整除时, n n n n − 1 n-1 n1 n − 3 n-3 n3互质

有人可能不服气,为什么又上面这几条性质。这里感兴趣的同学可以去搜一搜,但是本文不在此做出证明,因为还有方法二。

方法二:局部暴力

真正遇到这样的题,不知道方法一的数学公式怎么办?

没关系,贪心也能过。

首先想要乘机尽可能大,我们就要把这三个数取得尽可能大。

所以我们可以在 n n n的附近进行贪心。本题时间限制是 1 s 1s 1s,在这 1 s 1s 1s的时间里,进行 1 0 6 10^6 106的计算量不过分吧!

我们只需要在 [ max ⁡ ( 1 , n − 100 ) , n ] [\\max(1, n - 100), n] [max(1,n100),n]的范围内枚举 i , j , k i,j,k i,j,k,即可在 1 0 6 10^6 106级别的运算量中得到最优答案。

方法三:公式+无脑

方法二是无脑计算法,之所以采用方法二是因为“不知道方法一的数学公式”。其实我们只需要在 [ max ⁡ ( 1 , n − 3 ) , n ] [\\max(1, n - 3), n] [max(1,n3),n]的范围内枚举三个数即可得到最优答案。(暂且记为方法三:公式+无脑)

AC代码

方法一:数学公式

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int main() 
    ll n;
    cin >> n;
    if (n % 2) 
        cout << n * (n - 1) * (n - 2) << endl;
    
    else 
        if (n % 3 == 0) 
            cout << (n - 1) * (n - 2) * (n - 3) << endl;
        
        else 
            cout << n * (n - 1) * (n - 3) << endl;
        
    
    return 0;

方法二:局部暴力

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int main() 
    ll n;
    cin >> n;
    ll ans = 0;
    for (ll i = max(1ll, n - 100); i <= n; i++)
        for (ll j = max(1ll, n - 100); j <= n; j++)
            for (ll k = max(1ll, n - 100); k <= n; k++) 
                /*  // Error! 注释中是错误的求法 400 400 401的gcd为1,400*400*401/1/1 != 400 * 401
                    ll gcd = __gcd(__gcd(i, j), k);
                    ans = max(ans, i * j * k / gcd / gcd);
                    printf("i = %lld, j = %lld, k = %lld, __gcd(i, j, k) = %lld, GBS = %lld\\n", i, j, k, gcd, i * j * k / gcd / gcd);
                */
                ll thisAns = i * j / __gcd(i, j);
                thisAns = thisAns * k / __gcd(thisAns, k);
                ans = max(ans, thisAns);
            
    cout << ans << endl;
    return 0;

方法三:公式+无脑

运行时间大大缩短

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int main() 
    ll n;
    cin >> n;
    ll ans = 0;
    for (ll i = max(1ll, n - 3); i <= n; i++)
        for (ll j = max(1ll, n - 3); j <= n; j++)
            for (ll k = max(1ll, n - 3); k <= n; k++) 
                ll thisAns = i * j / __gcd(i, j);
                thisAns = thisAns * k / __gcd(thisAns, k);
                ans = max(ans, thisAns);
            
    cout << ans << endl;
    return 0;

每周提前更新菁英班周赛题解,点关注,不迷路

原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/125538415

以上是关于码蹄集 - MT3111· 赋值的主要内容,如果未能解决你的问题,请参考以下文章

码蹄集 - MT3435 · 赋值 - 二分图问题 - 图文讲解

算法竞赛入门码蹄集新手村600题(MT1501-1550)

码蹄集 - MT1258 · 特殊整数

算法竞赛入门码蹄集进阶塔335题(MT2286-2290)

算法竞赛入门码蹄集新手村600题(MT1401-1450)

算法竞赛入门码蹄集新手村600题(MT1201-1250)