题解:SP6556 NDIVPHI - N DIV PHI_N

题目传送门


题意简述

输入 \(20\) 个不超过 \(10^{40}\) 的数 \(n\),求最小的 \(m\) 使 \(\frac{m}{\phi(m)}\) 最大,其中 \(m \leq n\)

题目思路

前言:什么欧拉函数
\(\phi(x)\) 表示小于 \(x\)\(x\) 互质的非零自然数。

每一个非零自然数都可以写成几个质数相乘。如下:

\[x=\prod_{i=1}^{k}p_i^{c_i} \]

其中 \(p\) 表示质数,\(c_i\) 表示质数 \(p_i\) 指数。

那么欧拉函数的计算公式为:

\[\phi(x)=x\cdot \prod_{i=1}^{k}(1-\frac{1}{p_i}) \]

证明:

为了证明这个公式,我们可以考虑思考素数筛法工作的过程。在筛选过程中,我们会去掉所有质数的倍数。因为与一个数互质的数一定也与其质因子互质,对于每个质因子 \(p_i\),我们去掉的比例是 \(\frac{1}{p_i}\),因此保留的比例就是 \(1 - \frac{1}{p_i}\)。最终,所有素数的影响相乘,就得到了总的比例。

观察计算欧拉函数的式子,我们可以发现欧拉函数的值与每个质数的指数也就是 \(c_i\) 没有关系,所以答案的每一个 \(c_i\) 都为 \(1\)
因为 \(p\) 为质数时 \(\phi(p)=p-1\) ,所以每一个质数对答案的反贡献为 \(p-1\)。而我们希望反贡献越小越好,所以我们应取最小的几个质数之积。又因为 \(\prod_{i=1}^{28}p_i\)\(p_i\) 为质数)大于 \(10^{40}\)。所以我们可以先打前 \(28\) 个质数的升序表,然后求出最大的 \(x\),使 \(x=\prod_{i=1}^{k}p_i\)\(x\leq n\)\(x\) 为答案。

下面放第一个ACc++代码。

代码

#include<bits/stdc++.h>
using namespace std;
#define IFONLINEOJ false
#define IFONLUOGU false
namespace fast{
#if IFONLUOGU == false
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector")
#endif
#define il inline
#define re register
#define ri register int
#define ll long long
#if IFONLINEOJ
    static char buf[100000],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define int long long
#endif
    il void takefastout(){ios::sync_with_stdio(false);cout.tie(nullptr);}
    il int read(){
        ri x(0);    re char c=getchar();
        while(c>'9'||c<'0')c=getchar();
        while(c<='9'&&c>='0')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x;
    }
#undef int
}//加速
struct BigInteger {
    typedef unsigned long long LL;

    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<int> s;

    BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
    BigInteger(LL num = 0) {*this = num;}
    BigInteger(string s) {*this = s;}
    BigInteger& operator = (long long num) {
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    BigInteger& operator = (const string& str) {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; i++) {
            int end = str.length() - i*WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return (*this).clean();
    }

    BigInteger operator + (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    BigInteger operator - (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        for (int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = s[i] + g;
            if (i < b.s.size()) x -= b.s[i];
            if (x < 0) {g = -1; x += BASE;} else g = 0;
            c.s.push_back(x);
        }
        return c.clean();
    }
    BigInteger operator * (const BigInteger& b) const {
        int i, j; LL g;
        vector<LL> v(s.size()+b.s.size(), 0);
        BigInteger c; c.s.clear();
        for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
        for (i = 0, g = 0; ; i++) {
            if (g ==0 && i >= v.size()) break;
            LL x = v[i] + g;
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c.clean();
    }
    BigInteger operator / (const BigInteger& b) const {
        BigInteger c = *this; 
        BigInteger m;  
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
			m -= b*c.s[i];
        }
        return c.clean();
    }
    BigInteger operator % (const BigInteger& b) const {
        BigInteger c = *this;
        BigInteger m;
        for (int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return m;
    }
    int bsearch(const BigInteger& b, const BigInteger& m) const{
        int L = 0, R = BASE-1, x;
        while (1) {
            x = (L+R)>>1;
            if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
            else R = x;
        }
    }
    BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
    BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
    BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
    BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
    BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}

    bool operator < (const BigInteger& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (int i = s.size()-1; i >= 0; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    bool operator >(const BigInteger& b) const{return b < *this;}
    bool operator<=(const BigInteger& b) const{return !(b < *this);}
    bool operator>=(const BigInteger& b) const{return !(*this < b);}
    bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
    bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
ostream& operator << (ostream& out, const BigInteger& x) {
    out << x.s.back();
    for (int i = x.s.size()-2; i >= 0; i--) {
        char buf[20];
        sprintf(buf, "%08d", x.s[i]);
        for (int j = 0; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}
istream& operator >> (istream& in, BigInteger& x) {
    string s;if(!(in>>s)) return in;
    x = s;return in;
}//大数计算
const BigInteger prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107};
//质数表
int main(){
	for(ri i=0;i<20;i++){
		BigInteger n;	cin>>n;
		BigInteger ans=1ll;	ri cnt=0;
		while(ans<=n)	ans*=prime[cnt++];//计算
		cout<<ans/prime[cnt-1]<<'\n';
	}
	return 0;
}
posted @ 2025-04-18 14:27  _Charllote  阅读(33)  评论(0)    收藏  举报