题目大意:
有一张网格图,每个位置有至多
1
1
1个棋子。告诉你每一列有多少棋子
{
b
m
}
\{b_m\}
{bm},问有多少行的情况
{
a
n
}
\{a_n\}
{an}(即每一行有多少棋子),使得存在一种情况,满足这两个限制。
例如当
n
=
4
,
m
=
2
,
b
1
=
1
,
b
2
=
3
n=4,m=2,b_1=1,b_2=3
n=4,m=2,b1=1,b2=3的时候,
{
1
,
1
,
1
,
1
}
,
{
0
,
1
,
1
,
2
}
\{1,1,1,1\},\{0,1,1,2\}
{1,1,1,1},{0,1,1,2}及他们的多重排列共13中情况都是合法的(
{
0
,
1
,
1
,
2
}
\{0,1,1,2\}
{0,1,1,2}和
{
1
,
2
,
0
,
1
}
\{1,2,0,1\}
{1,2,0,1}被认为是两种方案)。
n
,
m
≤
50
,
b
i
≤
n
n,m\le50,b_i\le n
n,m≤50,bi≤n。
题解:
考虑告诉你
{
a
n
}
\{a_n\}
{an}怎么判定,其实这是另一个经典的问题,方法是先考虑朴素网络流,这个显然,然后转化为最小割,那么显然结果是,如果左边(行)选
x
x
x个,一定会选前
x
x
x小的,右边
y
y
y同理,记
s
a
[
x
]
sa[x]
sa[x]表示左边
a
a
a的前
x
x
x小,那么最小割是:
min
1
≤
x
≤
n
,
1
≤
y
≤
m
c
o
s
t
(
x
,
y
)
=
s
a
[
x
]
+
s
b
[
y
]
+
(
n
−
x
)
(
m
−
y
)
\min_{1\le x\le n,1\le y\le m}\ cost(x,y)=sa[x]+sb[y]+(n-x)(m-y)
1≤x≤n,1≤y≤mmin cost(x,y)=sa[x]+sb[y]+(n−x)(m−y)
(如果就是这样一个判定可行的题目的话,你可以用类似斜率优化和桶排做到线性判定)
现在我们希望最大流是
s
=
∑
i
=
1
m
b
i
s=\sum_{i=1}^m b_i
s=∑i=1mbi,也就是最小割是这个东西,那么就需要(显然一定存在一种割法使得代价是
s
s
s):
∀
x
,
y
,
c
o
s
t
(
x
,
y
)
≥
s
\forall x,y,cost(x,y)\geq s
∀x,y,cost(x,y)≥s
这样对于每个
x
x
x,我们就可以求出一个
s
a
[
x
]
sa[x]
sa[x]的下界,不妨记作
L
[
x
]
L[x]
L[x]。
然后我们就得到了能够使得
{
a
n
}
\{a_n\}
{an}有解的充要条件。
然后就可以
d
p
\mathrm{dp}
dp了,我们设
d
p
(
i
,
j
,
k
)
dp(i,j,k)
dp(i,j,k)表示填了
j
j
j行,最大值是
i
i
i,和是
k
k
k,那么枚举
t
t
t表示填
t
t
t行
i
+
1
i+1
i+1,并在剩下的
n
−
j
n-j
n−j行中选择
t
t
t行:
d
p
(
i
+
1
,
j
+
t
,
k
+
t
(
i
+
1
)
)
+
=
d
p
(
i
,
j
,
k
)
(
n
−
j
t
)
,
∀
p
∈
[
0
,
t
]
,
k
+
p
(
i
+
1
)
≥
L
[
k
+
p
]
dp(i+1,j+t,k+t(i+1))+=dp(i,j,k)\binom{n-j}{t},\\ \forall p\in[0,t],k+p(i+1)\geq L[k+p]
dp(i+1,j+t,k+t(i+1))+=dp(i,j,k)(tn−j),∀p∈[0,t],k+p(i+1)≥L[k+p]
注意转移的时候要满足第二行,不满足置
0
0
0(不合法)。
最后
d
p
(
m
,
n
,
s
)
dp(m,n,s)
dp(m,n,s)就是答案。
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define mod 1000000007
using namespace std;const int N=55;int b[N],L[N],dp[N][N][N*N],C[N][N];
int main()
{
int n,m;scanf("%d%d",&n,&m);rep(i,1,m) scanf("%d",&b[i]);sort(b+1,b+m+1);rep(i,1,m) b[i]+=b[i-1];
rep(x,1,n) rep(y,0,m) L[x]=max(L[x],b[m]-b[y]-(n-x)*(m-y));int s=b[m];
rep(i,0,n) C[i][0]=1;rep(i,1,n) rep(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
rep(i,0,n&&!L[i]) dp[0][i][0]=C[n][i];
rep(i,0,m-1) rep(j,0,n) rep(k,L[j],s-(n-j)*(i+1)) if(dp[i][j][k])
rep(t,0,n-j&&k+(i+1)*t<=s&&k+(i+1)*t>=L[j+t]) (dp[i+1][j+t][k+(i+1)*t]+=(lint)dp[i][j][k]*C[n-j][t]%mod)%=mod;
return !printf("%d\n",dp[m][n][s]);
}