BZOJ4715 囚人的旋律 DP

2022-05-20 07:53:01 字數 1406 閱讀 9969

我們令a[i]表示看守的第i扇門對應囚犯的哪一扇門。令圖g為有n個節點的圖,編號為1~n。對於滿足1≤ia[j],那麼在g中編號為i和j的節點之間連一條邊。得到的圖g被稱為逆序圖。對於圖g=(v,e),非空點集s∈v是乙個獨立集當且僅當對於任意兩個點u,v∈v,不存在(u,v)∈e。而s是乙個覆蓋集當且僅當對於任意點v?s存在點u∈s滿足(u,v)∈e。我們在意的是,圖g中有多少個點集既是獨立集又是覆蓋集。出於某種不知名的原因,被迫參加監獄遊戲的大家的安危和這個問題的答案有關。拜託了,請一定要求出這個方案數。

輸入第一行含有兩個整數n和m,表示逆序圖的點數和邊數。

接下來m行,每行描述一條邊。每行包含兩個1~n的整數,代表邊的兩個端點。保證沒有重邊和自環。

保證給定的圖是乙個合法的逆序圖,即,存在至少乙個序列,按照題目描述中所述方法得到的逆序圖是給定的圖。

n≤1000,0≤m≤(n(n-1))/2

輸出乙個整數,表示方案數對1,000,000,007取模得到的結果。

5 52 4

2 51 4

3 43 5

3題解:首先,根據這個逆序圖是可以在o(n^2)時間內將原序列還原出來的。

方法:統計每個數前面有多少個大於它的數pre,後面有多少個小於它的數nxt,那麼最小的數i一定滿足pre[i]=i-1&&nxt[i]=0,所以找出最小的數,然後將它刪掉,更新其它點的pre和nxt。不斷重複此過程即可。

那麼本題求的東西到底是什麼呢?一開始以為求的是邊覆蓋集,然後就變成了將原序列分成兩個不相交的上公升子串行,但是樣例過不去。。。後來發現求的是點覆蓋集。。。

因為選出來的序列是獨立集,所以這個序列是遞增的;又因為這是覆蓋集,所以每個不在序列中的點都與某個序列中的點形成逆序對。所以我們求的就是極長上公升序列的方案數!用f[i]表示前i個數中極長上公升序列方案數,如果i是乙個合法的結尾,則用f[i]更新答案即可。

#include #include #include using namespace std;

const int p=1000000007;

int n,m,ans;

int map[1010][1010],f[1010],nxt[1010],pre[1010],v[1010],bef[1010],aft[1010];

inline int rd()

while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();

return ret*f;

}int main()

for(i=1;i<=n;i++) for(j=i+1;j<=n;j++)

for(i=1;i<=n;i++)

{ for(k=1;k<=n;k++) if(!v[k]&&!nxt[k]&&pre[k]==k-1) break;

v[k]=i;

for(j=1;j

BZOJ4715 囚人的旋律 dp

非常有意思的 dp,很難想出來吧.如果對著圖去想,很難有思路,所以可以把圖上的問題轉化為序列問題.我們發現,如果乙個點集合法,當且僅當這個點集構成乙個不降序列,且其他點都與這個點集形成逆序對.令 f i 表示由 1 i 選 i 構成的合法方案數.然後如果不選乙個元素,顯然這個元素必須和距離該元素最近...

NOIP2013模擬10 23囚人的旋律

題目大意 給定乙個逆序圖,表示若a i a j i j 那麼i向j連一條邊 這裡是給定邊數 問有多少個選點方案,是的選定的點之間沒有連邊,沒選定的點與選定的點中至少乙個點有連邊。由於逆序圖能對應乙個序列,那麼我們將對應的圖轉成序列 題目保證 存在至少乙個序列 按照題目描述中所述方法得到的逆序圖是給定...

BZOJ4498 魔法的碰撞 DP

我們先考慮全部緊湊的情況,也就是沒有多餘的空格的情況 將d id i di 先不考慮魔法師佔的空間 這裡用了乙個很巧妙的方法,多加一維,表示預留的空位。加入a會有三種情況 e表示空位 a,ae或ea,eae。對於第一種,表示a兩邊都有魔法師。對於第二種,表示a的一邊有,一邊沒有。對於第三種,表示a的...