zoukankan      html  css  js  c++  java
  • 51nod 1779逆序对统计(状压DP)

    按照插入数的大小排序,

    然后依次进行dp。

    用一个状态表示n个数是否被选了

    10110 就是表示第1、3、4个位置都选了

    那么如果此时这个数该填到5这个位置,那么必定会造成一个逆序(因为下一个数会填到2,下一个数必定比这个数大)

    也就是转移的时候看插入位置前有多少个0,进行转移

    写的时候有一些小技巧

    (直接用记忆化统计0的个数超时了,这里有一个递推的技巧)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    int dp[2][(1<<20)+1], f[(1<<20)+1];
    int n, m, a[111];
    
    int main()
    {
        cin>>n>>m;
        for(int i = 1; i <= m; i++) cin>>a[i];
        for(int i = 0; i < n; i++) f[1<<i] = 1;
        for(int i = 0; i < (1<<n); i++) f[i] = f[i&-i]+f[i^(i&-i)];
        memset(dp[0], 128, sizeof(dp[0]));
        dp[0][0] = 0;
        int all = (1<<n)-1;
        for(int i = 1; i <= m; i++){
            for(int s = 0; s <= all; s++){
                if(dp[(i-1)&1][s] < 0) continue;
                dp[i&1][s] = max(dp[i&1][s], dp[(i-1)&1][s]);
                if((s&(1<<(n-a[i]))) == 0){
                    dp[i&1][s|(1<<(n-a[i]))] = max(dp[i&1][s|(1<<(n-a[i]))], dp[(i-1)&1][s] + (a[i]-1-f[s>>(n-a[i]+1)]));
                }
            }
            memset(dp[(i-1)&1], 128, sizeof(dp[(i-1)&1]));
        }
        cout<<dp[m&1][(1<<n)-1]<<endl;
        return 0;
    }
  • 相关阅读:
    新式类、经典类与多继承
    实现抽象类之方式二
    实现抽象类之方式一
    re模块
    28个高频Linux命令
    Git使用教程
    编程语言介绍
    编码
    进制
    操作系统简史
  • 原文地址:https://www.cnblogs.com/Saurus/p/6864235.html
Copyright © 2011-2022 走看看