我zxyoi學oi兩年,什麼場面沒見過。
這場面我真沒見過。
真正的dp好題,想清楚之後完全不難寫。
雖然寫完再去看覺得窒息得一批。
準確來說,這道題的考察內容就是揹包計數。
是的,只有揹包計數,除了乘法原理甚至可以說沒有任何組合數學內容。
純粹到極致的揹包dp神仙題。
設s
ss為s
ss之和,即總人數。
首先考慮低分暴力(因為正解裡面會用到)。
直接維護三位導師旗下的學員人數進行轉移,顯然第四位導師可以直接算出來,轉移複雜度o(n
m3
)o(nm^3)
o(nm3)
發現其實可以直接分陣營和派系維護,即我們只維護藍陣營和r派系的人數即可,複雜度o(n
m2
)o(nm^2)
o(nm2)
考慮k=
0k=0
k=0的情況。
我們重新理一遍題意,發現這種情況下陣營和派系的選擇互不影響。
分別揹包dp,設f[i
]f[i]
f[i]
表示藍陣營中人數為i
ii的方案數,g[i
]g[i]
g[i]
表示鴨派系中人數為j
jj的方案數。
則由乘法原理,答案為∑i=
s−c1
c0∑j
=s−d
1d0f
[i]g
[j
]\sum\limits_^\sum\limits_^f[i]g[j]
i=s−c1
∑c0
j=
s−d1
∑d0
f[
i]g[
j]接下來考慮存在某些學校討厭某個導師。
發現對於沒有任何乙個學校討厭某個導師的城市,和沒有討厭的導師的學校,這部分計數可以直接套用上面的做法。
然後對於有限制的,可以直接套用暴力解法。
列舉有限制的學校分在藍陣營,鴨派系的有多少人,剩下的部分直接乘法原理計算即可,需要維護一下上面揹包結果的字首和。
揹包過程中需要比較精細的上界優化,不然複雜度假的。
單組資料複雜度o((
c+n)
m+k2
sm
)o((c+n)m+k^2sm)
o((c+n
)m+k
2sm)
**:
#include
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace io
template
<
typename t>
inline t get()
inline
intgi()
}using
namespace io;
using std::cerr;
using std::cout;
cs int mod=
998244353
;inline
intadd
(int a,
int b)
inline
void
inc(
int&a,
int b)
cs int n=
1e3+
7,m=
2.5e3+7
;bool ban[n]
;int sum[n]
,hate[n]
,b[n]
,s[n]
;int f[m]
,f[m]
[m];
int g[m]
,g[m]
[m];
std::vector<
int> c[n]
;int n,c,c0,c1,d0,d1,tot,k;
inline
void
solve()
k=gi()
;while
(k--
)int lim=
0,tmp=0;
memset
(f,0
,sizeof
(int)*
(c0+1)
);f[0]
=1;lim=0;
for(
int re i=
1;i<=c;
++i)if(
!ban[i]
&&sum[i]
)for
(int re j=lim=std::
min(lim+
(tmp=sum[i]
),c0)
;j>=tmp;
--j)
inc(f[j]
,f[j-tmp]);
for(
int re i=
1;i<=c0;
++i)
inc(f[i]
,f[i-1]
);memset
(g,0
,sizeof
(int)*
(d0+1)
);g[0]
=1;lim=0;
for(
int re i=
1;i<=n;
++i)if(
!~hate[i]
)for
(int re j=lim=std::
min(lim+
(tmp=s[i]
),d0)
;j>=tmp;
--j)
inc(g[j]
,g[j-tmp]);
for(
int re i=
1;i<=d0;
++i)
inc(g[i]
,g[i-1]
);int cs=
0,ss=
0;f[0]
[0]=
1;for(
int re ct=
1;ct<=c;
++ct)
if(ban[ct])if
(hate[a]
>=2)
for(
int re i=
0;i<=cs;
++i)
for(
int re j=ss;j>=t;
--j)
inc(f[i]
[j],f[i]
[j-t]);
if(hate[a]==3
)for
(int re i=
0;i<=cs;
++i)
if(hate[a]
<=1)
for(
int re i=
0;i<=cs;
++i)
for(
int re j=ss;j>=t;
--j)
inc(g[i]
[j],g[i]
[j-t]);
}for
(int re j=
0,tmp=sum[ct]
;j<=ss;
++j)
for(
int re i=
0;i<=cs;
++i)
for(
int re j=
0;j<=ss;
++j)
inc(f[i]
[j],g[i]
[j]);}
int res=0;
for(
int re i=
0;i<=cs;
++i)
for(
int re j=
0;j<=ss;
++j)
cout<"\n"
;for
(int re i=
0;i<=cs;
++i)
memset
(f[i],0
,sizeof
(int)*
(ss+1)
),memset
(g[i],0
,sizeof
(int)*
(ss+1)
);}signed
main()
十二省聯考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 皮配
題目 十二省聯考2019 皮配 設s等於各學校人數之和。首先,有乙個很簡單的 o nm 2 的 dp 記錄當前考慮到哪所學校,以及藍陣營人數a,鴨派系人數b,最後,只要滿足 s c1 a c0 且 s d1 b d0 這個方案就是合法的。寫上這個就有50分了。注意到還有20分滿足 k 0 即沒有限制...