题意:给你 n , m n,m n,m,让你求满足对于每一列 j j j,满足 a [ i ] [ j ] = 0 , a [ i ] [ j + 1 ] = 1 a[i][j]=0,a[i][j+1]=1 a[i][j]=0,a[i][j+1]=1的 i i i不超过 k k k个的01矩阵的个数。
Solution
我的思路一开始跑偏了。
我把满足
a
[
i
]
[
j
]
=
0
,
a
[
i
]
[
j
+
1
]
=
1
a[i][j]=0,a[i][j+1]=1
a[i][j]=0,a[i][j+1]=1的点设置为
1
1
1,其他的点我设置为
0
0
0,然后我尝试以行为状态,但是这样的状态数高达一亿多,还要记录每一行满足条件的个数,感觉行不通,然后我有尝试以列为状态,这样可以不用在dp中记录k,感觉好一些,不过我发现计数的时候要统计每一行的1和改行前面的1的距离,其实这和以行为状态计算没有什么不同。后面我想起【CSP2019Emiya 家今天的饭】里面的补集转化,但是我思考很久以后发现也不行,我就被卡住了。
我有想了几个小时,突然灵机一动,感觉我不应该把满足
a
[
i
]
[
j
]
=
0
,
a
[
i
]
[
j
+
1
]
=
1
a[i][j]=0,a[i][j+1]=1
a[i][j]=0,a[i][j+1]=1的点设置为
1
1
1,因为这样不方便统计,所以我尝试直接用矩阵来做状态,其中很明显的是不能用行来当作状态,所以只能用列来做状态。我有仔细想想,对于列来说,转移的时候貌似之关注1的个数,并不在意1,0的具体位置,所以我令
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示第
i
i
i列0的个数为
j
j
j的方案数,预处理组合数以后直接暴力转移就好了。
Code
打代码时因为高精度乘高精度打错导致调了很久。。。
幸运的是0.98s刚好卡过去了。。。
#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
using namespace std;
template<typename T>inline void qr(T &x){
x=0;int f=0;char s=gc();
while(!isdigit(s))f|=s=='-',s=gc();
while(isdigit(s))x=x*10+s-48,s=gc();
x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
if(x<0)pc('-'),x=-x;
do{buf[++cc]=int(x%10);x/=10;}while(x);
while(cc)pc(buf[cc--]+'0');puts("");
}
const int N=42,md=1e4;
struct node{
int len,a[150];
node(){len=0;memset(a,0,sizeof(a));}
};
int n,m,k;
node c[N][N],f[N][N],ans;
node zh(int y){
node x;
while(y){
x.a[++x.len]=y%md;
y/=md;
}
return x;
}
node operator+(node x,node y){
node z;z.len=max(x.len,y.len);
rep(i,1,z.len){
z.a[i]+=x.a[i]+y.a[i];
z.a[i+1]+=z.a[i]/md;
z.a[i]%=md;
}
if(z.a[z.len+1])z.len++;
return z;
}
node operator*(node x,node y){
node z;
if(!x.len||!y.len)return z;
z.len=x.len+y.len-1;
rep(i,1,x.len)
rep(j,1,y.len)
z.a[i+j-1]+=x.a[i]*y.a[j];
rep(i,1,z.len){
z.a[i+1]+=z.a[i]/md;
z.a[i]%=md;
if(z.a[z.len+1])z.len++;
}
return z;
}
void prt(node x){
dwn(i,x.len,1){
if(i==x.len)printf("%d",x.a[i]);
else{
for(int j=100;j<=md;j*=10)
if(x.a[i]<j/10)pc('0');
printf("%d",x.a[i]);
}
}
}
int main(){
qr(n),qr(m),qr(k);
c[0][0]=zh(1);
rep(i,1,n){
c[i][0]=zh(1);
rep(j,1,i)c[i][j]=c[i-1][j-1]+c[i-1][j];
}
f[0][0]=zh(1);
rep(ki,1,1)
rep(i,0,n){
int now=n-i;
rep(j,0,n)
rep(l,0,j){
if(l>now||l>k)break;
f[ki][i]=f[ki][i]+f[ki-1][j]*c[j][l]*c[n-j][now-l];
}
}
rep(ki,2,m)
rep(i,0,n){
int now=n-i;
rep(j,0,n)
rep(l,0,j){
if(l>now||l>k)break;
f[ki][i]=f[ki][i]+f[ki-1][j]*c[j][l]*c[n-j][now-l];
}
}
rep(i,0,n)
ans=ans+f[m][i];
prt(ans);
return 0;
}