zoukankan      html  css  js  c++  java
  • 【【henuacm2016级暑期训练】动态规划专题 M】Little Pony and Harmony Chest

    【链接】 我是链接,点我呀:)
    【题意】

    在这里输入题意

    【题解】

    每一位显然只要取1..60这些数字。 然后需要保证每个这些数字里面,每个数字所用到的质因子都它所唯一拥有的。别人不能用 因为如果别人用了的话。gcd就不为1了。 因此我们肯定需要记录这些数字的质因子使用情况。 如果第i个位置枚举的数字,它里面的某个质因子,之前用过了。那么这个数字就不能用。 否则还可以用。 只需取前16个质数就能够表示1..60这些数字了 (其实只要取到58就好了,所以59这个质数不用,因为选59和选1的代价是一样的,而选60还不如选1呢。。。所以实际上是只要表示1..58这些数字 所以dp的状态第二维的大小为2^16 即f[i][j]表示前i个数字,选择的数字占用质因子的情况为j的最小代价。 预处理出来1..60这些数字占用质因子的情况(转成二进制),不预处理会超时。

    然后取minf[n][0..(1<<16)-1]
    可以加一个choose[n][1<<16]来记录每个决策选择的是哪个数字。方便后序输出。
    以及一个pre[n][1<<16]记录上一个决策点
    递归输出答案就好

    【代码】

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100;
    const int M = 16;
    const int INF = 0x3f3f3f3f;
    
    const int d[]= {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
    int f[N+10][1<<M],pre[N+10][1<<M],choose[N+10][1<<M],n,a[N+10];
    int pp[80];
    
    void output_ans(int dep,int i){
        if (dep==0) return;
        int prei = pre[dep][i];
        if (i==prei){
            output_ans(dep-1,i);
            cout<<1<<' ';
        }else{
            int temp = prei^i;
            output_ans(dep-1,prei);
            cout<<choose[dep][i]<<' ';
        }
    }
    
    int main() {
    	#ifdef LOCAL_DEFINE
    	    freopen("rush_in.txt", "r", stdin);
    	#endif
    	ios::sync_with_stdio(0),cin.tie(0);
    	memset(f,INF,sizeof f);
        cin >> n;
        for (int i = 1;i <= n;i++) cin >> a[i];
        f[0][0] = 0;//前0个数字 质数使用情况为
        for (int k = 1;k < 60;k++){
            int kk = 0;
            for (int l = 0;l < M;l++)
                if (k%d[l]==0){
                    kk+=(1<<l);
                }
            pp[k] = kk;
        }
        for (int i = 0;i <= n-1;i++)
            for (int j = 0;j < (1<<M);j++)
                if (f[i][j]<INF){
                    for (int k = 1;k < 60;k++){
                        int kk = pp[k];
    
                        if ((kk&j)==0){
                            int jj = kk|j;
                            if (f[i+1][jj]>f[i][j]+abs(k-a[i+1])){
                                f[i+1][jj] = f[i][j]+abs(k-a[i+1]);
                                choose[i+1][jj] = k;
                                pre[i+1][jj] = j;
                            }
                        }
                    }
                }
        int mi = INF,statu;
        for (int i = 0;i < (1<<M);i++)
            if (f[n][i]<mi){
                mi = f[n][i];
                statu = i;
            }
        output_ans(n,statu);
    	return 0;
    }
    
    
  • 相关阅读:
    将各种简单算法组合,使自己更加灵活的使用它
    转载 原反补码
    迭代器是神马东西
    进程 线程
    STL中的容器是如何实现的,如何存储的
    可以实例化对象,但是不能被继承的类
    float的存储及和int的转化
    对批处理、多道操作系统的理解
    STL set、map实现为什么要以红黑树为底层实现机制?
    c 多线程
  • 原文地址:https://www.cnblogs.com/AWCXV/p/9325861.html
Copyright © 2011-2022 走看看