【Heaven Cow与God Bull】题解

31 篇文章 0 订阅
6 篇文章 0 订阅
本文介绍了一个数学问题的求解方法,给定一个整数n,寻找一个不超过n的整数m,使得m与其欧拉函数之比m/phi(m)的值达到最大。文章详细阐述了解决这一问题的算法实现过程,包括如何通过预处理质数乘积提高计算效率。
摘要由CSDN通过智能技术生成

题目

Description

__int64 ago,there’s a heaven cow called sjy…
A god bull named wzc fell in love with her…
As an OI & MOer,wzc gave sjy a quesiton…
给定一个整数n,求一个整数m,满足m<=n,并且m/phi(m)的值最大。
注:phi(m)代表m的欧拉函数,即不大于m且与m互质的数的个数。

Input

第一行是一个整数T,表示该测试点有T组数据。
接下来T行,每行一个整数n,意义如上所述。

Output

输出一共T行,每行一个整数m。
若对于某个n,有不止一个满足条件的m,则输出最小的m。

Sample Input

1
10

Sample Output

6

Data Constraint

对于10%的数据, n<=1000
对于30%的数据, n<=10^10
对于60%的数据, n<=10^2000
对于100%的数据,T<=100,n<=10^25000。


分析

设pi为质数,m=p1^e1·p2^e2·p3^e3····。
我们首先来化简一下m/φ(m),容易得出m/φ(m)=(p1-1)(p2-1)(p3-1)···/p1·p2·p3····。
易证当p2>p1时,(p1-1)/p1>(p2-1)/p2,如果m取前k个质数的乘积,答案一定更优。答案就是最大的p1·p2·p3····。
如果边做边求p1·p2·p3····显然是不行的,所以先预处理p1·p2·p3····。大概60000以内的质数就可以,有6057个。为了缩短时间,高精度我压了11位,有点小恶心,事实上速度还是挺快的。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const long long maxlongint=2147483647;
const long long mo=100000000000;
using namespace std;
long long b[6500][2500],zs[6500],t,n,m,a[2500];
char s[100000];
int times(long long x,long long y,long value)
{
    long i,j,k,l;
    for(i=1;i<=b[x][0];i++)
    {
        b[y][i]+=b[x][i]*value;
        b[y][i+1]+=b[y][i]/mo;
        b[y][i]%=mo;
    }
    b[y][0]=b[x][0];
    if(b[y][b[y][0]+1]>0)
        b[y][0]++;
}
int bj(long long a[2500],long long b[2500])
{
    if(b[0]>a[0]) return true;
        if(b[0]<a[0]) return false;
            else
            {
                for(long long i=b[0];i>=1;i--)
                {
                    if(b[i]>a[i]) return true;
                        if(b[i]<a[i]) return false;
                }
            }
    return false;
}
int main()
{
    scanf("%lld\n",&t);
    long long i,j,k,l,x,y;
    for(i=2;i<=60000;i++)
    {
        bool q=true;
        for(j=2;j<=(long long)(sqrt(i));j++)
        {
            if(!(i%j)) q=false;
        }
        if(q)
        {
            zs[++zs[0]]=i;
        }
    }
    b[0][0]=1;
    b[0][1]=1;
    for(i=1;i<=zs[0];i++)//预处理
    {
        times(i-1,i,zs[i]);
    }
    while(t--)
    {
        scanf("%s\n",s);
        a[0]=0;
        k=0;
        int len=strlen(s);
        l=1;
        for(i=1;i<=len;i++)
        {
            k=k+(s[len-i]-48)*l;
            l*=10;
            if(l==mo)
            {
                a[++a[0]]=k;
                l=1;
                k=0;
            }
        }
        if(k)
            a[++a[0]]=k;
        for(i=1;i<=zs[0];i++)//O(6057)求答案。如果还想快点,可以二分
        {
            if(bj(a,b[i]))
            {
                for(j=b[i-1][0];j>=1;j--)
                {
                    if(j!=b[i-1][0])
                        printf("%011lld",b[i-1][j]);
                            else
                                printf("%lld",b[i-1][j]);
                }
                break;
            }
        }
        printf("\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值