加载中...

约数相关:约数个数

N=(p1c1)*(p2c2)...(pk^ck)
N2=(p1(c1**2)) * (p2^ (c2
2) )...(pk^ (ck2) )

约数个数 f[N]=(c1+1)(c2+1)...(cn+1)

拍打牛头https://www.acwing.com/problem/content/1293/

这里没有用到公式 只是将求约数转化成为求倍数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1000010;

int n;
int a[N], cnt[N], s[N];

int main()
{
    scanf("%d", &n);

    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &a[i]);
        cnt[a[i]] ++ ;//计数
    }

    for (int i = 1; i < N; i ++ )
        for (int j = i; j < N; j += i)//倍数都加一遍 包括自己
            s[j] += cnt[i];

    for (int i = 0; i < n; i ++ ) printf("%d\n", s[a[i]] - 1);

    return 0;
}

求满足x y是正整数的情况 1/x+1/y=(1/n)!的情况总数

https://www.acwing.com/problem/content/1296/
经过优化发现是求n!^2的约数之和的

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1e6 + 10, mod = 1e9 + 7;

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

void init(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] * i <= n; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

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

    init(n);

    int res = 1;
    for (int i = 0; i < cnt; i ++ )
    {
        int p = primes[i];
        int s = 0;
        for (int j = n; j; j /= p) s += j / p;
        res = (LL)res * (2 * s + 1) % mod;
    }

    cout << res << endl;


    return 0;
}


反素数https://www.acwing.com/problem/content/200/

1.最多会有9个质因子
2.每个质因子的次数最大是30
3.数字递增时候 所有质因子的次数一定递减

#include<iostream>
#include<cstring>
// #include<cstdio>由于这个题目的读入量很小,所以我们完全可以用cin来读
#include<algorithm>

using namespace std;

int primes[9]={2,3,5,7,11,13,17,19,23};//primes的话一共是有9个对吧

typedef long long LL;//当然这里要加一个long long 啊

int maxd;//比方说我们的约数个数可以记为我们的maxd

int number;//然后数本身的话可以记成number

int n;//然后还有一个n对吧,这是我们读入的这个数

void dfs(int u,int last,int p,int s)//好,那我们dfs一下,第u个质数,当前次数最大是last,当前数p,以及我们的约数个数s
{
    //好,然后如果我们当前的约数个数是大于我们的最大约数个数了
    //或者是等于等于最大约数个数并且p小于number的话
    if(s>maxd||s==maxd&&p<number)
    {
        maxd=s;//我们就要更新一下
        number=p;//然后number等于p,对吧
    }
    //好,接下来的话就去枚举一下啊
    //当然这里我们要判断一下啊,如果u已经的等于9了,表示已经枚举了所有情况了,那么我们就可以直接return了
    if(u==9)return;
    //然后接下来去枚举一下次数
    //次数的话咱们从一次开始枚举,一直枚举到第,last次对吧,不能比上一次多
    for(int i=1;i<=last;i++)//利用了会递减这个事实
    {
        if((LL)p*primes[u]>n)//那每次都先算一下我们这个这个,p乘上一个我们当前的质数,看一下是不是已经大于n了
        break;//大于n的话那就直接break就可以了对吧
        //好,然后否则的的话,咱们就让p就乘上一个primes[u]
        p*=primes[u];//i多少个就乘多少次primes[u]
        //好然后再dfs下一次
        dfs(u+1,i,p,s*(i+1));//u+1,然后是这个i,对吧,p,还有这个s*(i+1); 下一个位置的u

    }
}

int main()
{
    cin>>n;
    /*字            幕        开          始*/
    //首先dfs一遍
    //那么dfs里面是有几个参数呢?
    //第一个是我们枚举到第几个质数了,第0个对吧,从第0个开始枚举
    //然后下一个的话是我们的次数最大是多少对吧,那我们刚刚说了次数最大是30对吧,当前最大次数是30
    //然后我们这个数本身乘积是多少?这个乘积本身是1对吧
    //好,然后...(y总摸了摸鼻子和嘴唇继续说)呃...下一个,下一个应该是约数个数对吧,约数个数的话最开始是1对吧
    //因为我们约数个数是通过公式来算的,每次都要乘上一个数,所以在没乘之前应该是1
    dfs(0,30,1,1);
    //哦,忘记输出了咱们,咱们要把这个答案输出

    cout<<number<<endl;
    //好,840对吧,没问题
    return 0;
}


求一个数x 满足x和a最大公约数是b x和c最小公倍数是d https://www.acwing.com/problem/content/202/

因为 求1只需要看gcd 求2利用 两个自然数的最大公约数与它们的最小公倍数的乘积等于这两个数的乘积
所以对d分解质因数 那么x就是因数其中一个

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 45000, M = 50;

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

PII factor[M];
int cntf;

int divider[N], cntd;

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

void dfs(int u, int p)//已经知道质数p和次数s 爆搜出来所有的约数 u是当前的位置 p是乘的数
{
    if (u > cntf)
    {
        divider[cntd ++ ] = p;
        return;
    }

    for (int i = 0; i <= factor[u].second; i ++ )
    {
        dfs(u + 1, p);
        p *= factor[u].first;
    }
}

int main()
{
    get_primes(N);

    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a0, a1, b0, b1;
        scanf("%d%d%d%d", &a0, &a1, &b0, &b1);

        int d = b1;
        cntf = 0;
        for (int i = 0; primes[i] <= d / primes[i]; i ++ )
        {
            int p = primes[i];
            if (d % p == 0)
            {
                int s = 0;
                while (d % p == 0) s ++, d /= p;
                factor[ ++ cntf] = {p, s};
            }
        }
        if (d > 1) factor[ ++ cntf] = {d, 1};

        cntd = 0;
        dfs(1, 1);

        int res = 0;
        for (int i = 0; i < cntd; i ++ )
        {
            int x = divider[i];//对于每个约数x
            if (gcd(x, a0) == a1 && (LL)x * b0 / gcd(x, b0) == b1)//满足x和a最大公约数是b x和c最小公倍数是d 就是求 x*c/(xc的最大公约数是)
            {

                res ++ ;
            }
        }

        printf("%d\n", res);
    }

    return 0;
}

posted @ 2022-08-06 23:47  liang302  阅读(53)  评论(0编辑  收藏  举报