• LGTB 与序列


    LGTB 与序列(数论 (starstar ))

    • (LGTB) 有一个长度为 (N) 的序列 (A),现在他想构造一个新的长度为 (N) 的序列 (B),使得 (B) 中的任意两个数都互质。并且他要使

      [sum_{1le ile N}|A_i-B_i| ]

      最小,请输出最小值。

    Input

    • 第一行包含一个数 (N) 代表序列初始长度。
    • 接下来一行包含 (N) 个数 (A_1, A_2, …, A_N),代表序列 (A)

    Output

    • 输出包含一行,代表最小值。

    Sample Input

    5
    1 6 4 2 8
    

    Sample Output

    3
    

    Hint

    • 样例解释:(B={1,5,3,2,7})(1) 与任何数都互质。
    • 对于 (40\%) 的数据, (1 ≤ N ≤ 10)
    • 对于 (100\%) 的数据, (1 ≤ N ≤ 100, 1 ≤ A_i≤30)
    • 来源:

    分析

    • (A_ile 30 Rightarrow B_i le 58) ,因为 (B_i) 变成更大的数还不如直接取 (1),而且 (58) 之内只有 (16) 个素数。
    • 如果原数列中 (A_i>A_j),那么最优答案一定是 (B_i>B_j) 的情况。所以最多只有 (16) 个最大的数变成素数,其他的数都会变成 (1)
    • 所以直接对于前 (16) 个数 (dp, dp[i][j]) 代表到第 (i) 个数,哪些素因子被用过了,花费最少为多少。枚举一个数来转移即可

    Code

    #include <bits/stdc++.h>
    const int maxn=105,maxp=17,Inf=0x3f3f3f3f;
    int prime[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; // 16 primes
    int n,a[maxn];
    int dp[maxp][1<<maxp];
    int status[maxn];
    void Init(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        std::sort(a+1,a+n+1,std::greater<int>());
        memset(status,0,sizeof(status));
        for(int i=1;i<=58;i++)
            for(int j=1;j<=16;j++)
                if(i<prime[j]) break;
                else if(i%prime[j]==0)//分解质因数
                	status[i]|=(1<<j-1);//i的质因数情况
    }
    void Solve(){
        memset(dp,0x3f,sizeof(dp));
        dp[0][0]=0;
        for(int i=1;i<=std::min(n,16);i++)//最多处理最大的16个
            for(int S=0;S<(1<<16);S++) //枚举上一个状态
                for(int num=1;num<=58;num++)//枚举每一个可能的B[i]
                    if(!(status[num]&S)){//状态S中没有num的质因子
                    	int s=S|status[num];//num的质因数都并入下一个状态
                        dp[i][s]=std::min(dp[i][s],dp[i-1][S]+abs(a[i]-num));
                    }
        int ans=Inf;
        for(int S=0;S<(1<<16);S++)//枚举左后一行的所有状态
            ans=std::min(ans,dp[std::min(n,16)][S]);
        if(n>16)//剩下的均选1 
        	for(int i=17;i<=n;i++)
        		ans+=abs(a[i]-1);
        printf("%d
    ",ans);
    }
    int main(){    
        Init();
        Solve();    
        return 0;
    }
    
  • 相关阅读:
    printf打印输出null问题的跟踪
    一个需求的反思
    编写可测试的代码
    编写高质量代码_改善C++程序的150个建议 读书笔记
    GetDlgItem的用法小结
    引用作为函数返回值的一点思考
    LoadRunner 使用介绍
    撰写技术文章的注意事项
    NetLimiter网速测试小坑
    需求管理和开发的一点小思考
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13254009.html
Copyright © 2020-2023  润新知