• Luogu3943 星空 题解 状压+差分


    命运偷走如果 只留下结果
    时间偷走初衷 只留下了苦衷
    你来过 然后你走后 只留下星空

    这道题的主要思路是差分+状压dp,不需要额外的毒瘤数据结构..
    如果我们将原序列定义为暗灯的是1,亮灯为0,差分为数组(book),那么(book)中的1的个数一定是偶数个;
    我们定义(c_i)为要使(i)个反转至少需要翻多少次(不可能则为(INF)),然后(c)数组可以用dp/递推预处理出来,
    然后将原题转化成在差分数组中,每一次都可以选择两个距离为(i)的"1", 然后将他们以消耗(c_i)的代价变成0;
    当然,可能对于两个值为1的位置(c[i] == INF)这样的话不能一次将2个1变为0,而是可以将另外的0变成1...
    这个可以用状压DP来求解,设(dp[S])为状态为(S)的时候最小需要翻的步数.
    注意这里的S并不是表示的是差分数组每个位置的翻与否,而是表示的是位置为1的翻与否,0则是没有翻,而我们的目的是把这些是1的位置全都翻成0,所以最后的答案是将他们都翻:(dp[(1<<cnt)-1]).

    具体细节看代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define N 100005
    #define M 128
    using namespace std;
    
    int n, K, m, a[N], b[N], book[N], f[N], c[N], Lg[N];
    long long g[1 << 17];
    
    inline int lowbit(int x) {
        return x & (-x);
    }
    
    int main() {
        cin >> n >> K >> m;
        for (int i = 1; i <= K; ++i)
            scanf("%d", a + i);
        for (int i = 1; i <= m; ++i)
            scanf("%d", b + i);
        for (int i = 1; i <= K; ++i)
            book[a[i]] ^= 1, book[a[i] + 1] ^= 1;
        int cnt = 0;
        for (int i = 1; i <= n + 1; ++i)
            if (book[i]) c[++cnt] = i;
        memset(f, 0x3f, sizeof f);
        f[0] = 0;
        for (int j = 1; j <= m; ++j)
            for (int i = 1; i <= n; ++i)
                if (i - b[j] >= 0)
                    f[i] = min(f[i], f[i - b[j]] + 1);
        for (int j = 1; j <= m; ++j)
            for (int i = n; i >= 1; --i)
                if (i + b[j] <= n)
                    f[i] = min(f[i], f[i + b[j]] + 1);
        for (int i = 1; i < (1 << cnt); ++i)
            g[i] = 1e12;
        g[0] = 0;
        for (int S = 0; S < (1 << cnt); ++S) {
            int u = 0;
            while (S & (1 << u)) ++u;
            for (int v = u + 1; v < cnt; ++v) {
                if (((1 << v) & S)) continue;
                long long &t = g[(S | (1 << u)) | (1 << v)];
                t = min(t, g[S] + f[c[v + 1] - c[u + 1]]);
            }
        }
        cout << g[(1 << cnt) - 1] << endl;
        return 0;
    }
    
  • 相关阅读:
    UML用例图
    directX--大约CSource和CSourceStream (谁在叫fillbuffer)
    【云】如何建立微信在全国卖场地图?
    C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序
    Android使用SVG矢量创建很酷的动态效率!
    观察者模式(observer行为)c#简单的例子
    Oracle MySQL
    tomcat 跨域
    Jms Spring
    Ehcache使用
  • 原文地址:https://www.cnblogs.com/hnfms-jerry/p/solution-luogu-starlit.html
Copyright © 2020-2023  润新知