1. 程式人生 > >【51nod】1779 逆序對統計 狀壓DP

【51nod】1779 逆序對統計 狀壓DP

題目傳送門

這題好迷啊,一直都看不懂題目意思……(就不能TMD說的清楚點嗎?)

題目大意:有n個位置和m道題目,第i道題目的權值為i,可以放在第a[i]位上,求最大逆序對數。

看到資料範圍裡n20,瞬間想到了狀壓,果真如此。

定義f[j]表示當前狀態為j的最大逆序對。

我們順序讀入m道題目,顯然權值單調遞增,即每道題目能和所有在它之前、放在它之後的題目形成逆序對。

對於一道題目i,我們列舉狀態時把第a[i]個位置空出來,計算一下當前狀態中[a[i]+1,j]中有多少位置為1,並進行一下狀態的轉移。

因為題目保證每道題都存在至少一個分數檔次,所以直接輸出f[(1<<n)

1]即可。

附上AC程式碼:

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;

int n,m,x,f[1048576];

inline char nc(void){
    static char ch[100010],*p1=ch,*p2=ch;
    return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int
&a){ static char c=nc();int f=1; for (;!isdigit(c);c=nc()) if (c=='-') f=-1; for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc()); return (void)(a*=f); } int main(void){ read(n),read(m); for (int i=1; i<(1<<n); ++i) f[i]=-2e9; while (m--){ read(x),--x; for
(int i=0; i<(1<<n); ++i) if ((i>>x&1)==0&&f[i]!=-2e9){ int sum=0; for (int j=x+1; j<=n; ++j) sum+=i>>j&1; f[i|(1<<x)]=max(f[i|(1<<x)],f[i]+sum); } } return printf("%d",f[(1<<n)-1]),0; }