数学知识(2)

 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int x;
        cin>>x;
        int res=x;
        for(int i=2;i<=x/i;i++)
        {
            if(x%i==0)
            {
                res=res/i*(i-1);
                while(x%i==0) x/=i;
            }
        }
        if(x>1) res=res/x*(x-1);
        cout<<x<<endl;
    }
}

 

/*
如果用上道题做法,对每个数直接用公式求解,对每个数都要分解质因数,时间复杂度是n*sqrt(n)
可以用线性筛法用O(n)时间复杂度顺便求出每个数的欧拉函数
线性筛法可以顺便求出来很多东西

用处:欧拉定理
若a与n互质,则a^(n的欧拉函数)模n等于1
推论:当n是质数时 a^(n-1)模n等于1 费马定理
*/
#include <iostream>

using namespace std;

typedef long long LL;

const int N = 1000010;


int primes[N], cnt;
int euler[N];
bool st[N];


void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])//如果当前这个数没有被筛过,说明i是一个质数
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;//质数i的欧拉函数就是i-1
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
/*
求欧拉函数过程中,只有这个数包含某个质因子,就乘(1-1/pj),与这个质因子的次数没有关系
比如6的欧拉函数==6*(1-1/2)(1-1/3)  
另外一个数n==2^100 * 3^100,它的欧拉函数==n*(1-1/2)(1-1/3),和次数无关

primes[j] * i的欧拉函数与i的欧拉函数的关系:

当i % primes[j] == 0时,primes[j]是i的最小质因子,也是primes[j] * i的最小质因子,
所以primes[j] * i与i的质因子是相同的,所以euler[primes[j] * i] = euler[i] * primes[j]

当i % primes[j] != 0时,primes[j]小于i的最小质因子,是primes[j] * i的最小质因子,
euler[primes[j] * i] == euler[i] * primes[j] * (primes[j] - 1) / primes[j]
                     == euler[i] * (primes[j] - 1)
*/
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}


int main()
{
    int n;
    cin >> n;

    get_eulers(n);

    LL res = 0;//和可能很大,会报int,所以用ll来存
    for (int i = 1; i <= n; i ++ ) res += euler[i];

    cout << res << endl;

    return 0;
}

/*
快速求出来 a^k mod p,时间复杂度 O(logk)
核心思路是反复平方,预处理出来a^(2^0) mod p,a^(2^1) mod p,...a^(2^logk) mod p
把a^k mod p 拆成前面预处理的logk个数的乘积,k转换成二进制
*/
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


LL qmi(int a, int b, int p)
{
    LL res = 1 % p;
    while (b)
    {
        if (b & 1) res = res * a % p;//凡是中间结果可能会溢出的地方,都要特殊处理
        a = a * (LL)a % p;
//a * (LL)a % p和(LL)a * a % p 第2个的a∗p可能爆int,所以(LL)写到中间是个好习惯
        b >>= 1;//删掉最后一位
    }
    return res;
}


int main()
{
    int n;
    cin>>n;
    while (n -- )
    {
        int a, b, p;
        cin>>a>>b>>p;
        cout<<qmi(a, b, p)<<endl;
    }

    return 0;
}

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

LL qmi(int a, int b, int p)
{
    LL res = 1;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * (LL)a % p;
        b >>= 1;
    }
    return res;
}

int main()
{
    int n;
    cin>>n;
    while (n -- )
    {
        int a, p;
        cin>>a>>p;
        if (a % p == 0) puts("impossible");// a是p的倍数时无解
        else cout<<qmi(a, p - 2, p)<<endl;
    }

    return 0;
}

/*
求x, y,使得ax + by = gcd(a, b)
裴蜀定理
对于任意正整数a,b 那么一定存在非零整数x,y使得ax + by = gcd(a, b)
如果ax + by = d 则d一定是gcd(a, b)的倍数
*/
#include <iostream>
#include <algorithm>

using namespace std;
/*
int gcd(int a, int b)
{
    if (!b)
    {
        return a;
    }
    return gcd(b, a % b);
}
*/
int exgcd(int a, int b, int &x, int &y)//后两者传引用
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;//x不变,y-= a / b * x
    return d;
}

int main()
{
    int n;
    cin>>n;

    while (n -- )
    {
        int a, b;
        cin>>a>>b;
        int x, y;
        exgcd(a, b, x, y);
        cout<<x<<' '<<y<<endl;
    }

    return 0;
}

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}


int main()
{
    int n;
    cin>>n;
    while (n -- )
    {
        int a, b, m;
        cin>>a>>b>>m;

        int x, y;
        int d = exgcd(a, m, x, y);//扩展欧几里得算法求出最大公约数d
        if (b % d) puts("impossible");//b能够整除最大公约数d有解
        else cout<<(LL)b / d * x % m<<endl;//x扩大若干倍模到m范围内即可
    }

    return 0;
}

 

/*
推导见
https://www.acwing.com/solution/content/3539/
https://www.acwing.com/solution/content/23099/
*/

#include<iostream>

using namespace std;

typedef long long LL;//数据范围比较大,所以用LL来存储

LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    LL d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

int main()
{
    int n;
    LL a1,m1;
    cin>>n>>a1>>m1;
    LL x=0;
    for(int i=1;i<n;i++)
    {
        LL a2,m2;
        cin>>a2>>m2;
        LL k1,k2;
        LL d=exgcd(a1,a2,k1,k2);
        if((m2-m1)%d)//无解
        {
            x=-1;
            break;
        }
        k1*=(m2-m1)/d;
        //因为此时k1是k1*a1+k2*a2=d的解,所以要乘上(m2-m1)/d的倍数大小
        LL t=abs(a2/d);
        k1=(k1%t+t)%t;
        //数据比较极端,所以只求k的最小正整数解
        m1=k1*a1+m1;
        //m1在被赋值之后的值为当前"x"的值,此时赋值是为了方便下一轮的继续使用
        a1=abs(a1*a2/d);
        //循环结束时a1的值为当前所有的a1,a2,……an中的最小公倍数
    }
    if(x!=-1) x=(m1%a1+a1)%a1;
    //当循环结束时,此时的值应该与最小公倍数取模,以求得最小正整数解
    cout<<x<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值