zoukankan      html  css  js  c++  java
  • codeforces 453B B. Little Pony and Harmony Chest (状压dp+数论)

    题目链接:

    http://codeforces.com/contest/453/problem/B

    题意:

    给出一个序列a,求取一个序列b,b序列的数两两互质,问能够导致|aibi|最小的方案

    思路:

    http://blog.csdn.net/qq_24451605/article/details/48878237 orz

    • 定义状态dp[i][j]表示前i个数达到j状态的最小的结果,j状态表示已经被用过的质数。
    • 因为当一个a的数据范围不超过30,所以如果某个数超过60,那么选择1一定比它更优,所以我们能够用到的数的质因子也一定不会超过60,也才17个,所以我们只需要每次枚举数,然后通过之前的状态进行转移即可。
    • 具体转移过程见代码。
    • 为了得到方案,我们记录了pre[i][j]代表前i个数达到状态j得到最大值的前一个状态,num[i][j]表示前i个数达到状态j得到最大值的最后选取的数字。 

    state[k] 表示k的所有质因子,用了k,就不能用所有k的质因子了

    转移: dp[i+1][x] = min(dp[i+1][x],dp[i][j]+abs(a[i+1]-k))  【 b[i+1]=k;  x=state[k] | j 】

    为什么对质数进行状压嘞?首先不同的质数是可以选的,一个质数只能用一次,那么如何分辨非质数是否可选? 其实就是判断这个非质数A的质因子是否已经用过了,假如前面已经选了一个非质数B,那么如果A与B有公因子x,即使x不是质数,也一定可以分解成质数,这样只需判断质数是否用过就好了。

    挺有收获的,状压状压!!!

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define MS(a) memset(a,0,sizeof(a))
    #define MP make_pair
    #define PB push_back
    const int INF = 0x3f3f3f3f;
    const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    //////////////////////////////////////////////////////////////////////////
    const int maxn = 1e5+10;
    
    int n,a[105];
    int dp[105][1<<16],pre[105][1<<16],num[105][1<<16],state[105];
    
    int prime[20] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
    
    void print(int x,int st){
        if(x == 1){
            printf("%d ",num[x][st]);
            return ;
        }
        
        print(x-1,pre[x][st]);
        printf("%d ",num[x][st]);
    }
    
    int main(){
        cin >> n;
        for(int i=1; i<=n; i++)
            cin >> a[i];
        memset(dp,INF,sizeof(dp));
        dp[0][0] = 0;
    
        for(int k=2; k<59; k++){
            for(int j=0; j<16; j++)
                if(k%prime[j] == 0)
                    state[k] |= (1<<j);
        }
        int tot = 1<<16;
        for(int i=0; i<n; i++){
            for(int j=0; j<tot; j++){
                if(dp[i][j]==INF) continue;
                for(int k=1; k<59; k++){
                    if(state[k]&j) continue;
                    int x = state[k]|j;
                    if(dp[i+1][x] > dp[i][j]+abs(a[i+1]-k)){
                        dp[i+1][x] = dp[i][j]+abs(a[i+1]-k);
                        pre[i+1][x] = j;
                        num[i+1][x] = k;
                    }
                }
            }
        }
        int minn = INF,st;
        for(int j=0; j<tot; j++){
            if(minn > dp[n][j]){
                minn = dp[n][j];
                st = j;
            }
        }
        print(n,st);
        puts("");
    
        return 0;
    }
  • 相关阅读:
    HanLP《自然语言处理入门》笔记--5.感知机模型与序列标注
    Netty系列-netty的Future 和 Promise
    Netty系列-netty的初体验
    CentOS7 源码编译安装Nginx
    linux 源码编译安装MySQL
    Linux CentOS7
    Linux CentOS7 搭建ntp时间同步服务器
    CentOS7-7搭建ftp服务器
    CentOS7-7 搭建dhcp服务器
    python批量扫描脚本
  • 原文地址:https://www.cnblogs.com/yxg123123/p/7143713.html
Copyright © 2011-2022 走看看