寒假集训——Index of super-prime 和 北航9届校赛晴天小猪爱61

Index of super-prime题目链接

Index of super-prime题意:首先定义一个超级素数,素数是2 3 5.。。  而超级素数是在所有的素数中编号也是素数的,比如3 5 (编号是2, 3),给出一个数n~10000,如果这个数不能只用超级素数的和表示,输出0,如果可以,输出个数最少的情况。

题解:首先筛素数,然后根据素数搞出来超级素数。之后能否达到n,其实就是用已经有的超级素数作为物品,用完全背包去达到n,dp表示最少的个数,额外用from来记录转移过来的状态。

爱61的题解:很大的时候,可以拆成。。。XXX61 + 61XX,一定可以构造成,那么当小于6161时,就要考虑了,很小的时候,先考虑本身就有61的,用这些作为物品来达到n,也是一个完全背包。

重点:将一个数字在一定要求下拆分成满足限制的数字,就是完全背包。注意爱61题目的思维,构造很重要的,然后枚举,然后0背包。

下面的代码是Index of super-prime,并且dp不是习惯的完全背包写的。。。以要达到的数字i为基础,枚举到底最后一个数是加上谁。。。以后直接完全背包就好了= =

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 1e4 + 1000;
const int INF = INT_MAX/2 - 1;
int vis[maxn], prime[maxn], super_prime[maxn], prime_n, super_prime_n;
int is_super_prime[maxn];

void getSuperPrime()//搞到超级素数
{
    prime_n = 0;
    CLR(vis);
    CLR(is_super_prime);
    for(int i = 2; i <= 10000; i++)
    {
        if(!vis[i])
        {
            prime[++prime_n] = i;
            for(int j = i; j <= 10000; j += i)
            {
                vis[j] = 1;
            }
        }
    }
    super_prime_n = 0;
    for(int i = 1; prime[i] <= prime_n; i++)
    {
        super_prime[++super_prime_n] = prime[prime[i]];
    }
    for(int i = 1; i <= super_prime_n; i++)
    {
        is_super_prime[super_prime[i]] = 1;
    }
}

int n, num[maxn], first[maxn], ans[maxn];

void getDp()//以后用完全背包
{
    num[0] = 0;
    for(int i = 1; i <= 10000; i++)
    {
        int tmp_n = INF, tmp_f;
        if(is_super_prime[i])
        {
            num[i] = 1;
            first[i] = i;
            continue;
        }
        for(int j = 1; (super_prime[j] <= i&&j <= super_prime_n); j++)
        {
            if(num[i - super_prime[j]] + 1 < tmp_n)
            {
                tmp_n = num[i - super_prime[j]] + 1;
                tmp_f = super_prime[j];
            }
        }
        num[i] = tmp_n;
        first[i] = tmp_f;
    }
}

bool cmp(int a, int b)
{
    return a > b;
}
int main()
{
  //  freopen("4Din.txt", "r", stdin);
    //freopen("4Dout.txt", "w", stdout);
    getSuperPrime();
    getDp();
    while(scanf("%d", &n) != EOF)
    {
        if(num[n] != INF)
        {
            int ans_n = 0;
            int lft;
            lft = n;
            printf("%d\n", num[n]);
            while(lft!=0)
            {
                ans[ans_n++] = first[lft];
                lft -= first[lft];
            }
            sort(ans, ans + ans_n, cmp);
            for(int i = 0;i < ans_n;i++)
            {
                printf("%d%c", ans[i], (i == ans_n - 1 ? '\n' : ' '));
            }
        }
        else
        {
            printf("0\n");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值