AcWing1296. 聪明的燕姿

聪明的燕姿

解题思路:

首先我们肯定要用到约数之和定理

但是有个问题就是要怎么用

根据经验得知,约数最多也就六七个左右,不然直接就超了s的范围。所以我们考虑用爆搜来做

但是用爆搜的话还是要优化一下思路和用什么顺序去搜索。

顺序:

按照p和α的顺序来枚举

一旦s%这个当前的乘积==0(dfs的精髓)

那才能跳到下一层循环因为这样才符合约数和定理

dfs的精髓:当前条件满足,然后递归到下一层。到最后一层的时候又满足条件。然后跳出递归

可能要想一些剪枝:

  1. 当s等于1+p的时候,直接就得到一个答案。这样就可以少遍历几个

小于s的质数的个数有s除以logn个

时间复杂度:\(O(10\sqrt{S}*100)\)

十个约数,然后再判断质数的个数。k组数据

y总的代码

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

using namespace std;

const int N = 50000;

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

int ans[N], len;

void get_primes(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;
        }
    }
}

bool is_prime(int x)
{
    if (x < N) return !st[x];
    for (int i = 0; primes[i] <= x / primes[i]; i ++ )
        if (x % primes[i] == 0)
            return false;
    return true;
}

void dfs(int last, int prod, int s)
{
    if (s == 1)
    {
        ans[len ++ ] = prod;
        return;
    }
    
    if (s - 1 > (last < 0 ? 1 : primes[last]) && is_prime(s - 1))
        ans[len ++ ] = prod * (s - 1);  // 不可以写primes[last]因为可能是第一个
    
    for (int i = last + 1; primes[i] <= s / primes[i]; i ++ )
    {
        int p = primes[i];
        for (int j = 1 + p, t = p; j <= s; t *= p, j += t)
            if (s % j == 0)
                dfs(i, prod * t, s / j);
    }
}

int main()
{
    get_primes(N - 1);
    
    int s;
    while (cin >> s)
    {
        len = 0;
        dfs(-1, 1, s);
        
        cout << len << endl;
        if (len)
        {
            sort(ans, ans + len);
            for (int i = 0; i < len; i ++ ) cout << ans[i] << ' ';
            cout << endl;
        }
    }
    
    return 0;
}

解题技巧创造出来

算法创造出来比较少

自己的代码

#include<cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 50000 + 10;
int ans[maxn], len, cnt;
int primes[maxn];
bool st[maxn];


void get_primes(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;
        }
    }
}

bool is_prime(int n)
{
    if(n < maxn) return !st[n];
    for(int i = 0; primes[i] <= n / primes[i]; i++)
    {
        if(n % primes[i] == 0) return false;
    }
    return true;
}


void dfs(int last, int prod, int s)
{
    if(s == 1)
    {
        ans[len++] = prod;
        return ;
    }
    if(is_prime(s - 1) && s - 1 > (last < 0 ? 1 : primes[last])) ans[len++] = prod * (s - 1); // primes[last + 1]的话可能会出错
    for(int i = last + 1; primes[i] <= s / primes[i]; i++)
    {
        int p = primes[i];
        for(int j = 1 + p, t = p; j <= s; t*=p, j += t)
        {
            if(s % j == 0)  dfs(i, prod * t, s / j);
        }
    } 
}

int main()
{
    get_primes(maxn);
    int s;
    while(~scanf("%d", &s))
    {
        len = 0;
        dfs(-1, 1, s);
        cout << len << endl;
        if(len)
        {
            sort(ans, ans + len);
            for(int i = 0; i < len ; i++) printf("%d ", ans[i]);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/WalterJ726/p/12372942.html