• Luogu P3943 星空 (差分思想 + 背包 + 状压DP)


    差分是个常用的技巧,翻转连续的一段0101序列很容易想到翻转异或差分序列上的两个数。

    差分序列上最多有2k2k11,并且肯定是偶数个。每次可以消除两个11,消除的代价与这两个11的距离相关,求将所有11消除的最小代价。

    消除的代价用完全背包或者BFSBFS都可以求出。用完全背包求消除代价,相当于把每个可以翻转的长度xx,看做体积分别为xxx-x的两个物品。

    只有T2k16Tleq 2kleq 16个需要翻转的11,直接状态压缩DPDP即可。

    每次转移时可以先固定选择最小的位置,然后再枚举另一个位置。

    时间复杂度O(NM+2TT)mathcal{O}(NM+2^T T)

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 4e4 + 5;
    const int MAXS = (1<<16) + 5;
    int n, k, m, t, p[16], b[65], w[MAXN], f[MAXS], cnt[MAXS], s;
    
    int main()
    {
        scanf("%d%d%d", &n, &k, &m); ++n;
        for (int i = k, j = -1, x; i--; j=x) {
        	scanf("%d", &x);
            if(x == j+1) p[t-1] = x+1;
            else p[t++]=x, p[t++] = x+1;
    	}
        memset(w,63,sizeof(w)), w[0] = 0;
    	for(int i = 1; i <= m; ++i)
    		scanf("%d", &b[i]);
        for(int i = 1; i <= m; ++i)
            for(int j = b[i]; j <= n; ++j)
                w[j] = min(w[j], w[j-b[i]]+1);
        for(int i = 1; i <= m; ++i)
            for(int j = n-b[i]; j >= 0; --j)
                w[j] = min(w[j], w[j+b[i]]+1);
        memset(f,63,sizeof(f)), f[0]=0;
        s = (1<<t)-1;
        for(int i = 1; i <= s; ++i) {
            if((cnt[i]=cnt[i>>1]+(i&1))&1) continue;
            int j = 0, x; while(!((i>>j)&1))++j;
            x=i^(1<<j);
            for(int k = j+1; k <= t-1; ++k)
                if((x>>k)&1) f[i] = min(f[i], f[x^(1<<k)] + w[p[k]-p[j]]);
        }
        printf("%d", f[s]);
        return 0;
    }
    
  • 相关阅读:
    android driver开发常见的英文缩写
    简析quakeIII中利用链表实现的内存管理(1)
    链表的建立
    boson netsim5.31平台上组建交换式网络
    第六周周记
    价值观作业
    C语言的知识与能力的自评
    学习进度表
    Web表格部分内容
    线性表部分知识
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039236.html
Copyright © 2020-2023  润新知