十二省聯考2019 皮配

2022-06-20 14:15:10 字數 3014 閱讀 7220

題目:[十二省聯考2019]皮配

設s等於各學校人數之和。

首先,有乙個很簡單的\(o(nm^2)\)的\(dp\):記錄當前考慮到哪所學校,以及藍陣營人數a,鴨派系人數b,最後,只要滿足\(s-c1<=a<=c0\)且\(s-d1<=b<=d0\),這個方案就是合法的。

寫上這個就有50分了。

注意到還有20分滿足\(k=0\),即沒有限制,考慮這部分的做法:

我們發現,對於乙個城市,無論選擇哪個陣營,其中的學校都可以去鴨派系或 r 派系。

換句話說,陣營與派系互不影響。

所以,可以對陣營與派系分別\(dp\),然後乘起來即可。時間複雜度為\(o(nm)\)。

這樣就有70分了。然而考場上寫錯了這20分,只有50。

考慮100分做法:

我們發現:k的範圍很小(只有30),這意味著有很多城市的所有學校都是沒有限制的。

所以,對於這些城市,我們可以使用\(k=0\)的方法計算。這部分時間複雜度為\(o(nm)\)。

考慮其餘的城市:

因為乙個城市可能有很多學校,所以這些城市可能有很多學校,不能暴力。

但是,如果乙個學校沒有限制,那麼選擇派系的情況不受陣營干擾。

所以,我們拿出這些城市中沒有限制的學校,只對b(派系)做dp。這部分時間複雜度為\(o(nm)\)。

再考慮有限制的學校:

首先,這些學校選擇派系的情況陣營干擾,所以不能用之前的方法dp。

但是,這些學校只有k個,可以使用50分的暴力dp。這部分時間複雜度為\(o(km^2)\),使用滾動陣列,卡卡常就不會超時。

在這次dp中,就把上次dp的結果考慮進去,相當於合併揹包。

最後\(o(m^2)\)合併揹包即可。總時間複雜度為\(o(km^2)\)。

注意細節,注意卡常。

**:

#include #include #define md 998244353

#define max(a,b) (a>b?a:b)

#define min(a,b) (a0?(sua[r]-sua[l-1]+md)%md:sua[r])

#define getsub(l,r) (l>0?(sub[r]-sub[l-1]+md)%md:sub[r])

using namespace std;

int f[1010][2510],he[2510],sz[2510],ty[2510],wz[2510];

int ta[2510],tb[2510],tc[2510],ts[2510];

int g[2510][2510][2],sua[2510],sub[2510],c0,c1,d0,d1;

bool bk[2510],jd[2510];

bool ya[2][4]=;

bool rr[2][4]=;

vector < int > ve[2510];

int main()

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

scanf("%d", &k);

for (int i = 0; i < k; i++)

if (s - c1 > c0 || s - d1 > d0)

for (int i = 0; i <= n; i++)

f[i][j] = f[i - 1][j];

if (j >= sz[i] && !bk[wz[i]]) f[i][j] = (f[i][j] + f[i - 1][j - sz[i]]) % md;

}} for (int i = 0; i <= d0; i++) tb[i] = f[n][i];

for (int i = 0; i <= c; i++)

f[i][j] = f[i - 1][j];

if (j >= he[i] && he[i] != 0 && !bk[i]) f[i][j] = (f[i][j] + f[i - 1][j - he[i]]) % md;

}} for (int i = 0; i <= c0; i++) ta[i] = f[c][i];

for (int i = 0; i <= c0; i++)

for (int i = 0; i <= d0; i++)

int m = 0;

for (int i = 1; i <= c; i++) }}

} for (int i = 0; i <= m; i++)

f[i][j] = f[i - 1][j];

if (j >= sz[ts[i]]) f[i][j] = (f[i][j] + f[i - 1][j - sz[ts[i]]]) % md;

}} for (int i = 0; i <= d0; i++) tc[i] = f[m][i];

m = 0;

for (int i = 1; i <= c; i++)

}jd[la] = true;

}} for (re int i = 0, ha = 0, hb = ms; i <= k; i++)

re int la = g[a][b][c];

g[a][b][c] = 0;

if (jd[ts[i]])

g[a][b][c] %= md;

if (ya[1][ty[ts[i]]] && b >= sz[ts[i]]) g[a][b][c] = (g[a][b][c] + g[a][b - sz[ts[i]]][1]) % md;

if (rr[1][ty[ts[i]]]) g[a][b][c] = (g[a][b][c] + (c == 0 ? g[a][b][1] : la)) % md;

} else else

g[a][b][c] %= md;}}

}}

} re int ans = 0;

for (int d = 0; d <= c0; d++)

} for (int a = 0; a <= c0; a++)

} printf("%d\n", ans);

} return 0;

}

十二省聯考2019 皮配

十二省聯考2019 皮配 巧妙運用 獨立 的性質,對於 不獨立 的進行暴力處理,再合併 1.dp i j k 前i個城市,藍有j,鴨有k個方案數 2.無限制時,城市的陣營和學校的派系獨立,直接dp出城市選擇方案,派系選擇方案,直接乘起來。顯然唯一分配且一一對應 有限制,只有30個 考慮對於有限制的城...

十二省聯考 2019 皮配

你有 n 個集合,每個集合裡有一些非負整數。有 4 個桶,現在要把每個非負整數放入其中 1 個桶。限制條件 1.同一集合的所有數要麼都放入第 1,2 個桶,要麼都放入第 3,4 個桶。2.有 k 個數有特殊要求 不能放入前 2 個桶或不能放入後 2 個桶。3.設 cnt i 為第 i 個桶放的數的總...

十二省聯考 2019 皮配

這是一道揹包計數問題,所以可以從生成函式的角度來理解。每個選手可選擇的是陣營 0 1 以及派系 0 1 如果乙個城市選擇了第 i 陣營第 j 派系,那麼相當於分別讓陣營 i 和派系 j 的代價 s i 設乙個沒有任何限制的學校的生成函式為 1 x y x y 其中 x 表示陣營 1 y 表示派系 1...