• 10.24testT3


    序列
    seq.cpp/in/out
    1s / 32M
    【题目描述】
    山山有一个长度为 N 的序列 A,现在他想构造一个新的长度为 N 的序列
    B,使得 B 中的任意两个数都互质。
    并且他要使


    请输出最小值。
    最小。
    【输入格式】
    第一行包含一个数 N 代表序列初始长度
    接下来一行包含 N 个数 A1 , A2 ,..., AN ,代表序列 A
    【输出格式】
    输出包含一行,代表最小值
    【样例输入】
    5
    1 6 4 2 8
    【样例输出】
    3
    【样例说明】
    样例中 B 数组可以为 1 5 3 1 8
    【数据范围】
    对于 40% 的数据,1 ≤ N ≤ 10
    对于 100% 的数据,1 ≤ N ≤ 100,1 ≤ ai ≤ 30

    分析:最开始拿到这个题,我采取了暴搜+剪枝的策略。然而时间复杂度太高,只拿了部分分。

    首先题目要求你构造一个序列,使所有元素互质,从此我们可以提取出一个性质:所有元素的素数因子都不相同。

    题目又要求,构造出的序列与原序列的差值的绝对值之和最小。而对于两个已知序列的排列,当且仅当两序列rank一一对应时满足。将原数组从大到小排序后,构造出的数组也一定是不降的。

    考虑到ai最多变成58,如果变成更大的数还不如变成1,而且58之内只有16个素数 并且可以证明对于两个数a > b,变成的数A >= B

    所以最多只有16个最大的数变成素数,其他的数都会变成1。

    所以直接对于前16个数dp,dp[i][j]代表到第i个数,状压哪些素因子被用过了,花费最少为多少。枚举一个数来转移即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n,tim,f[20][1<<17],ans=0x3f3f3f3f,a[110],x[20],p[20],yz[70];
    bool vis[70];
    bool cmp(const int &a,const int &b)
    {
        return a>b;
    }
    void kk()
    {
        int t=sqrt(60);
        for(int i=2;i<=t;i++)
        if(!vis[i]){
            for(int j=i*i;j<=60;j+=i)
            vis[j]=1;
        }
        for(int i=2;i<=60;i++)
        if(!vis[i])x[++tim]=i;
    }
    int main()
    {
        scanf("%d",&n);
        p[0]=1;
        for(int i=1;i<=20;i++)p[i]=p[i-1]<<1;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n,cmp);
        kk();
        for(int i=2;i<=58;i++)
        {
        for(int j=1;j<=tim;j++)
            if(i%x[j]==0)
            yz[i]|=p[j-1];
        }
        int nn=min(n,16);
        memset(f,0x3f3f3f3f,sizeof(f));
        f[0][0]=0;
        for(int i=1;i<=nn;i++)//枚举已经处理到第几项了
        for(int j=0;j<=p[16]-1;j++)//前i项包含的素数因子的状态
            if(f[i-1][j]<0x3f3f3f3f)
            {
            f[i][j]=min(f[i][j],f[i-1][j]+abs(a[i]-1));
            for(int k=2;k<=58;k++)//枚举下一项的取值
                if((j&yz[k])==0)
                f[i][j|yz[k]]=min(f[i][j|yz[k]],f[i-1][j]+abs(a[i]-k));
            }
        for(int i=0;i<=p[16]-1;i++)ans=min(ans,f[nn][i]);
        for(int i=nn+1;i<=n;i++)ans+=abs(a[i]-1);
        printf("%d\n",ans);
        return 0;
    }
  • 相关阅读:
    剑指Offer-用两个栈实现队列
    剑指Offer-从尾到头打印链表
    滑动门技术实现
    解决keil5中文注释乱码方法
    faker数据填充详解
    redis在微博与微信等互联网应用笔记
    JDBC插入中文数据出现?号地解决问题
    idea配置less自动编译
    idea使用Vue的v-bind,v-on报错
    idea 代码部分格式化
  • 原文地址:https://www.cnblogs.com/lxykk/p/7723319.html
Copyright © 2020-2023  润新知